import Phaser from 'phaser';
import {
    PLAYER_GRAVITY,
    PLAYER_JUMP_VELOCITY,
    PLAYER_MAX_SPEED,
    PLAYER_ACCELERATION,
    PLAYER_MAX_JUMPS,
    RESPAWN_INVINCIBILITY_TIME,
} 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;

    constructor(scene: Phaser.Scene, x: number, y: number) {
        // Pour l'instant, utiliser un sprite simple
        // TODO: Remplacer par le spritesheet du neveu
        super(scene, x, y, 'player');

        // 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.setSize(40, 70); // Hitbox
        body.setMaxVelocity(PLAYER_MAX_SPEED, 1000);
        // Aligner la hitbox en bas du sprite (80x169 par défaut)
        body.setOffset((this.width - 40) / 2, (this.height || 169) - 70);

        // Temporaire : créer un rectangle coloré si pas de texture
        if (!scene.textures.exists('player')) {
            this.createPlaceholderTexture(scene);
        }

        this.setOrigin(0.5, 1); // Origine en bas au centre
        body.setOffset((this.width - 40) / 2, (this.height || 169) - 70); // aligner la hitbox en bas

        this.ensureAnimations();
        this.setTexture('player_walk_1'); // frame par défaut
    }

    /**
     * Crée une texture temporaire pour le joueur
     */
    private createPlaceholderTexture(scene: Phaser.Scene): void {
        const graphics = scene.add.graphics();
        graphics.fillStyle(0xFF0000, 1);
        graphics.fillRect(0, 0, 50, 80);
        graphics.generateTexture('player', 50, 80);
        graphics.destroy();

        this.setTexture('player');
    }

    /**
     * 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
            if (this.animationsCreated && this.anims.get('player-jump')) {
                this.anims.play('player-jump', true);
            }

            // 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 });

            // TODO: Jouer son de saut (différent pour double saut)
            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;
        }

        // TODO: Jouer les animations appropriées
        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;

        // Transition sol -> air : jouer l'anim jump une fois
        if (isAir && !this.wasAir) {
            const jumpAnim = this.anims.get('player-jump');
            if (jumpAnim) {
                this.anims.play('player-jump', true);
            }
        }

        // Sol : choisir walk ou idle
        if (!isAir) {
            if (isMoving) {
                this.anims.play('player-walk', true);
            } else {
                this.anims.play('player-idle', true);
            }
        } else {
            // En l'air : si pas d'anim jump, forcer dernière frame jump
            if (this.anims.currentAnim?.key !== 'player-jump' && this.anims.get('player-jump')) {
                this.anims.play('player-jump', 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)
     */
    private ensureAnimations(): void {
        if (this.animationsCreated) return;

        const scene = this.scene;
        const walkFrames = ['player_walk_1', 'player_walk_2', 'player_walk_3', 'player_walk_4']
            .filter((key) => scene.textures.exists(key))
            .map((key) => ({ key }));
        const jumpFrames = ['player_jump_1', 'player_jump_2', 'player_jump_3', 'player_jump_4', 'player_jump_5']
            .filter((key) => scene.textures.exists(key))
            .map((key) => ({ key }));

        if (walkFrames.length >= 2) {
            scene.anims.create({
                key: 'player-walk',
                frames: walkFrames,
                frameRate: 10,
                repeat: -1,
            });

            scene.anims.create({
                key: 'player-idle',
                frames: [{ key: walkFrames[0].key }],
                frameRate: 1,
                repeat: -1,
            });
        }

        if (jumpFrames.length >= 2) {
            scene.anims.create({
                key: 'player-jump',
                frames: jumpFrames,
                frameRate: 12,
                repeat: 0,
            });
        }

        this.animationsCreated = walkFrames.length >= 2 || jumpFrames.length >= 2;
    }

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