import Phaser from 'phaser';
import {
    PLAYER_GRAVITY,
    PLAYER_JUMP_VELOCITY,
    PLAYER_MAX_SPEED,
    PLAYER_ACCELERATION,
    PLAYER_MAX_JUMPS,
    RESPAWN_INVINCIBILITY_TIME,
    USER1_HITBOX,
    USER2_HITBOX,
} from '../utils/constants';

/**
 * Classe du joueur
 * Gère le mouvement, les animations, et les collisions
 */
export class Player extends Phaser.Physics.Arcade.Sprite {
    private velocityX: number = 0;
    private jumpCount: number = 0; // Compteur de sauts (pour double saut)
    private isInvincible: boolean = false; // Invincibilité temporaire après respawn
    private invincibilityTimer?: Phaser.Time.TimerEvent;
    private animationsCreated: boolean = false;
    private wasAir: boolean = false;
    private playerPrefix: string = 'player_user1'; // Préfixe pour les sprites (user1 ou user2)

    constructor(scene: Phaser.Scene, x: number, y: number) {
        // Récupérer le joueur sélectionné depuis le registry
        const selectedPlayer = scene.registry.get('selectedPlayer') as string | undefined;
        const playerPrefix = selectedPlayer === 'user2' ? 'player_user2' : 'player_user1';

        // Utiliser le spritesheet comme texture de base
        const spritesheetKey = selectedPlayer === 'user2' ? 'player_user2' : 'player_user1';
        super(scene, x, y, spritesheetKey, 0); // Frame 0 du spritesheet

        // Stocker le préfixe pour utilisation ultérieure
        this.playerPrefix = playerPrefix;

        // Ajouter à la scène
        scene.add.existing(this);
        scene.physics.add.existing(this);

        // Configuration physique
        const body = this.body as Phaser.Physics.Arcade.Body;
        body.setGravityY(PLAYER_GRAVITY);
        body.setCollideWorldBounds(true); // Collision avec les limites du monde
        body.onWorldBounds = true; // Active les événements de collision
        body.setMaxVelocity(PLAYER_MAX_SPEED, 1000);

        this.setOrigin(0.5, 1); // Origine en bas au centre
        this.setScale(1); // Échelle 1:1 pour les deux joueurs

        // Utiliser la configuration de hitbox spécifique au joueur
        const hitboxConfig = selectedPlayer === 'user2' ? USER2_HITBOX : USER1_HITBOX;

        // Attendre que le sprite soit complètement initialisé pour configurer la hitbox
        this.scene.time.delayedCall(0, () => {
            const spriteWidth = this.width;
            const spriteHeight = this.height;

            // Centrer la hitbox horizontalement
            const offsetX = (spriteWidth - hitboxConfig.width) / 2;
            // Placer la hitbox en bas du sprite
            const offsetY = spriteHeight - hitboxConfig.height;

            body.setSize(hitboxConfig.width, hitboxConfig.height);
            body.setOffset(offsetX, offsetY);

            console.log(`🎯 Hitbox FINALE configurée pour ${this.playerPrefix}:`, {
                selectedPlayer,
                spriteActualSize: `${spriteWidth}x${spriteHeight}px`,
                hitboxSize: `${hitboxConfig.width}x${hitboxConfig.height}px`,
                offset: `x=${offsetX.toFixed(1)}, y=${offsetY.toFixed(1)}px`
            });
        });

        this.ensureAnimations();

        // Définir la frame par défaut (idle = première frame du spritesheet)
        this.setFrame(0);
    }


    /**
     * Met à jour le mouvement du joueur
     * @param direction -1 (gauche), 0 (immobile), 1 (droite)
     */
    public move(direction: number): void {
        const body = this.body as Phaser.Physics.Arcade.Body;

        // Accélération progressive
        if (direction !== 0) {
            this.velocityX += direction * PLAYER_ACCELERATION;
            this.velocityX = Phaser.Math.Clamp(
                this.velocityX,
                -PLAYER_MAX_SPEED,
                PLAYER_MAX_SPEED
            );
        } else {
            // Décélération quand pas d'input
            this.velocityX *= 0.9;
            if (Math.abs(this.velocityX) < 1) {
                this.velocityX = 0;
            }
        }

        body.setVelocityX(this.velocityX);

        // Orientation du sprite
        if (this.velocityX < -10) {
            this.setFlipX(true);
        } else if (this.velocityX > 10) {
            this.setFlipX(false);
        }

        // Animation (quand les sprites seront disponibles)
        this.updateAnimation();
    }

    /**
     * Fait sauter le joueur (avec support du double saut)
     */
    public jump(): void {
        const body = this.body as Phaser.Physics.Arcade.Body;

        // Réinitialiser le compteur de sauts au sol
        if (body.touching.down) {
            this.jumpCount = 0;
        }

        // Autoriser le saut si on n'a pas dépassé le nombre max de sauts
        if (this.jumpCount < PLAYER_MAX_JUMPS) {
            body.setVelocityY(PLAYER_JUMP_VELOCITY);
            this.jumpCount++;

            // Déclencher l'anim de saut immédiatement si disponible
            const jumpAnimKey = `${this.playerPrefix}-jump`;
            const animExists = this.scene.anims.exists(jumpAnimKey);
            console.log(`🦘 Tentative de saut #${this.jumpCount}: anim "${jumpAnimKey}" existe = ${animExists}, animationsCreated = ${this.animationsCreated}`);

            if (this.animationsCreated && animExists) {
                this.anims.play(jumpAnimKey, true);
                console.log(`✅ Animation de saut jouée: ${jumpAnimKey}`);
            } else {
                console.warn(`⚠️ Animation de saut non disponible: ${jumpAnimKey}`);
            }

            // Effet sonore de saut (volume global SFX depuis le registry)
            const sfxVolume = (this.scene.registry.get('sfxVolume') as number | undefined) ?? 1;
            this.scene.sound.play('sfx_jump', { volume: 0.5 * sfxVolume });

            console.log(`Saut ${this.jumpCount}/${PLAYER_MAX_JUMPS}`);
        }
    }

    /**
     * Met à jour les animations selon l'état
     */
    private updateAnimation(): void {
        const body = this.body as Phaser.Physics.Arcade.Body;

        // Réinitialiser le flag de saut et le compteur si on touche le sol
        if (body.touching.down) {
            this.jumpCount = 0;
        }

        if (!this.animationsCreated) return;

        const isMoving = Math.abs(this.velocityX) > 10;
        const bodyState = this.body as Phaser.Physics.Arcade.Body;
        const isAir = !bodyState.touching.down;

        // Utiliser les clés d'animation spécifiques au joueur
        const walkAnimKey = `${this.playerPrefix}-walk`;
        const idleAnimKey = `${this.playerPrefix}-idle`;
        const jumpAnimKey = `${this.playerPrefix}-jump`;

        // Transition sol -> air : jouer l'anim jump une fois
        if (isAir && !this.wasAir) {
            if (this.scene.anims.exists(jumpAnimKey)) {
                this.anims.play(jumpAnimKey, true);
            }
        }

        // Sol : choisir walk ou idle
        if (!isAir) {
            if (isMoving) {
                if (this.scene.anims.exists(walkAnimKey)) {
                    this.anims.play(walkAnimKey, true);
                }
            } else {
                // Jouer idle uniquement si on n'est pas déjà en train de le jouer
                if (this.anims.currentAnim?.key !== idleAnimKey) {
                    if (this.scene.anims.exists(idleAnimKey)) {
                        this.anims.play(idleAnimKey, true);
                    } else {
                        // Fallback : afficher directement la frame 0 du spritesheet
                        this.anims.stop();
                        this.setFrame(0);
                    }
                }
            }
        } else {
            // En l'air : si pas d'anim jump, forcer dernière frame jump
            if (this.anims.currentAnim?.key !== jumpAnimKey && this.scene.anims.exists(jumpAnimKey)) {
                this.anims.play(jumpAnimKey, true);
            }
        }

        this.wasAir = isAir;
    }

    /**
     * Retourne si le joueur est au sol
     */
    public isOnGround(): boolean {
        const body = this.body as Phaser.Physics.Arcade.Body;
        return body.touching.down;
    }

    /**
     * Retourne la vitesse horizontale actuelle
     */
    public getVelocityX(): number {
        return this.velocityX;
    }

    /**
     * Active l'invincibilité temporaire (après respawn)
     */
    public makeInvincible(scene: Phaser.Scene): void {
        this.isInvincible = true;

        // Effet visuel clignotant
        scene.tweens.add({
            targets: this,
            alpha: 0.3,
            duration: 150,
            yoyo: true,
            repeat: Math.floor(RESPAWN_INVINCIBILITY_TIME / 300),
            onComplete: () => {
                this.alpha = 1;
            },
        });

        // Timer d'invincibilité
        if (this.invincibilityTimer) {
            this.invincibilityTimer.destroy();
        }

        this.invincibilityTimer = scene.time.delayedCall(RESPAWN_INVINCIBILITY_TIME, () => {
            this.isInvincible = false;
            console.log('Invincibilité terminée');
        });
    }

    /**
     * Vérifie si le joueur est invincible
     */
    public getIsInvincible(): boolean {
        return this.isInvincible;
    }

    /**
     * Update appelé chaque frame
     */
    public update(): void {
        // Logique supplémentaire si nécessaire
    }

    /**
     * Création des animations (walk + idle + jump) selon le joueur sélectionné
     */
    private ensureAnimations(): void {
        if (this.animationsCreated) return;

        const scene = this.scene;
        const selectedPlayer = scene.registry.get('selectedPlayer') as string | undefined;

        // Utiliser le préfixe du joueur (player_user1 ou player_user2)
        const walkFrameKeys = [
            `${this.playerPrefix}_walk_1`,
            `${this.playerPrefix}_walk_2`,
            `${this.playerPrefix}_walk_3`,
            `${this.playerPrefix}_walk_4`
        ];

        const jumpFrameKeys = [
            `${this.playerPrefix}_jump_1`,
            `${this.playerPrefix}_jump_2`,
            `${this.playerPrefix}_jump_3`,
            `${this.playerPrefix}_jump_4`,
            `${this.playerPrefix}_jump_5`
        ];

        // Debug: vérifier quelles textures existent
        console.log(`🔍 Vérification des textures pour ${this.playerPrefix}:`);
        walkFrameKeys.forEach(key => {
            const exists = scene.textures.exists(key);
            console.log(`  Walk frame "${key}": ${exists ? '✅' : '❌'}`);
        });
        jumpFrameKeys.forEach(key => {
            const exists = scene.textures.exists(key);
            console.log(`  Jump frame "${key}": ${exists ? '✅' : '❌'}`);
        });

        const walkFrames = walkFrameKeys
            .filter((key) => scene.textures.exists(key))
            .map((key) => ({ key }));

        const jumpFrames = jumpFrameKeys
            .filter((key) => scene.textures.exists(key))
            .map((key) => ({ key }));

        // Créer des clés d'animation uniques par joueur
        const walkAnimKey = `${this.playerPrefix}-walk`;
        const idleAnimKey = `${this.playerPrefix}-idle`;
        const jumpAnimKey = `${this.playerPrefix}-jump`;

        if (walkFrames.length >= 2) {
            // Vérifier si l'animation existe déjà avant de la créer
            if (!scene.anims.exists(walkAnimKey)) {
                scene.anims.create({
                    key: walkAnimKey,
                    frames: walkFrames,
                    frameRate: 10,
                    repeat: -1,
                });
            }
        }

        // Animation idle : utilise la frame 0 du spritesheet (pose debout)
        const spritesheetKey = selectedPlayer === 'user2' ? 'player_user2' : 'player_user1';
        if (!scene.anims.exists(idleAnimKey)) {
            scene.anims.create({
                key: idleAnimKey,
                frames: [{ key: spritesheetKey, frame: 0 }],
                frameRate: 1,
                repeat: -1,
            });
        }

        if (jumpFrames.length >= 2) {
            if (!scene.anims.exists(jumpAnimKey)) {
                scene.anims.create({
                    key: jumpAnimKey,
                    frames: jumpFrames,
                    frameRate: 12,
                    repeat: 0,
                });
                console.log(`✅ Animation de saut créée: ${jumpAnimKey} avec ${jumpFrames.length} frames`);
            }
        } else {
            console.warn(`⚠️ Pas assez de frames pour l'animation de saut (${jumpFrames.length}/2 requis)`);
        }

        this.animationsCreated = walkFrames.length >= 2 || jumpFrames.length >= 2;
        console.log(`🎬 Animations ${this.playerPrefix}:`, {
            walk: walkFrames.length,
            jump: jumpFrames.length,
            created: this.animationsCreated
        });
    }

    /**
     * Nettoie les ressources
     */
    destroy(): void {
        if (this.invincibilityTimer) {
            this.invincibilityTimer.destroy();
        }
        super.destroy();
    }
}
