import Phaser from 'phaser';
import { LEVEL_DURATION, PLAYER_STARTING_LIVES, CHEST_REQUIRED_GIFTS, MIN_MUSHROOMS } from '../utils/constants';
import { Player } from '../entities/Player';
import { GyroControl } from '../controls/GyroControl';
import { JumpButton } from '../controls/JumpButton';
import { DirectionalButtons } from '../controls/DirectionalButtons';
import { SuperTreasure } from '../entities/SuperTreasure';
import { TreasureChest } from '../entities/TreasureChest';
import { Cage } from '../entities/Cage';

/**
 * Scène principale du jeu
 * Supporte PC (clavier) et Mobile (gyroscope + tactile)
 */
export class GameScene extends Phaser.Scene {
    private player?: Player;
    private cursors?: Phaser.Types.Input.Keyboard.CursorKeys;
    private gyroControl?: GyroControl;
    private jumpButton?: JumpButton;
    private directionalButtons?: DirectionalButtons;

    // Plateformes et groupes
    private platforms?: Phaser.Physics.Arcade.StaticGroup;
    private obstacles?: Phaser.Physics.Arcade.Group;
    private gifts?: Phaser.Physics.Arcade.Group;
    private superTreasures?: Phaser.Physics.Arcade.Group;
    private treasureChest?: TreasureChest;
    private cage?: Cage;
    private hasKey: boolean = false;
    private bgMusic?: Phaser.Sound.BaseSound;
    private platformRects: { x: number; y: number; w: number; h: number }[] = [];

    // Background
    private background?: Phaser.GameObjects.TileSprite;

    // UI
    private scoreText?: Phaser.GameObjects.Text;
    private timerText?: Phaser.GameObjects.Text;
    private controlInfoText?: Phaser.GameObjects.Text;
    private livesText?: Phaser.GameObjects.Text;
    private giftsCollectedText?: Phaser.GameObjects.Text;
    private volumeText?: Phaser.GameObjects.Text;
    private sfxVolumeText?: Phaser.GameObjects.Text;
    private debugText?: Phaser.GameObjects.Text;
    private lastDebugUpdate: number = 0;
    private gyroDebugButton?: Phaser.GameObjects.Text;
    private gyroDomButton?: HTMLButtonElement;
    private recalibrateDomButton?: HTMLButtonElement;

    // Game state
    private score: number = 0;
    private timeRemaining: number = LEVEL_DURATION;
    private gameStartTime: number = 0;
    private isMobile: boolean = false;
    private lives: number = PLAYER_STARTING_LIVES;
    private giftsCollected: number = 0;
    private lastCheckpointX: number = 200; // Position du dernier checkpoint
    private musicVolume: number = 0.5;
    private sfxVolume: number = 0.6;
    private snowPileTimer?: Phaser.Time.TimerEvent;
    private snowHeights: number[] = [];
    private snowPileGraphics?: Phaser.GameObjects.Graphics;

    constructor() {
        super({ key: 'GameScene' });
    }

    create(): void {
        const width = this.cameras.main.width;
        const height = this.cameras.main.height;

        // Réinitialiser l'état de partie
        this.score = 0;
        this.giftsCollected = 0;
        this.lives = PLAYER_STARTING_LIVES;
        this.lastCheckpointX = 200;

        this.gameStartTime = this.time.now;

        // Détecter si mobile
        this.isMobile = this.sys.game.device.os.android || this.sys.game.device.os.iOS;

        // Configurer les limites du monde physique (IMPORTANT pour permettre mouvement infini)
        // Étendre encore plus pour inclure la cage du chien après le coffre
        const levelWidth = Math.max(width * 7, 10500); // Augmenté de 2500px
        this.physics.world.setBounds(0, 0, levelWidth, height);

        // Créer le background qui défile
        this.createBackground(levelWidth);

        // Créer les plateformes
        this.createPlatforms();

        // Créer le joueur
        this.player = new Player(this, 200, height - 150);

        // Collision joueur / plateformes (one-way platforms)
        // Le joueur peut passer par en dessous mais atterrit par le dessus
        this.physics.add.collider(this.player, this.platforms!, undefined, (playerObj, platformObj) => {
            const player = playerObj as Phaser.GameObjects.GameObject;
            const platform = platformObj as Phaser.GameObjects.GameObject;

            const playerBody = (player as any).body as Phaser.Physics.Arcade.Body;
            const platformBody = (platform as any).body as Phaser.Physics.Arcade.Body;

            if (!playerBody || !platformBody) return true;

            const isGround = (platform as any).getData?.('isGround') === true;
            if (isGround) return true;

            // Autoriser la collision uniquement si le joueur vient du dessus
            // (sa vitesse verticale est positive = tombe, et son bas est au-dessus du haut de la plateforme)
            return playerBody.velocity.y >= 0 && playerBody.bottom <= platformBody.top + 10;
        });

        // Créer les groupes d'objets
        this.createObjectGroups();

        // Configuration caméra (suit le joueur)
        this.cameras.main.startFollow(this.player, true, 0.1, 0.1);
        this.cameras.main.setBounds(0, 0, levelWidth, height);

        // Contrôles PC (clavier)
        this.cursors = this.input.keyboard?.createCursorKeys();
        console.log('[GameScene] 🎮 Cursors initialized:', this.cursors ? '✅' : '❌',
                    'Left:', !!this.cursors?.left, 'Right:', !!this.cursors?.right, 'Space:', !!this.cursors?.space);

        // Contrôles Mobile (gyroscope + bouton tactile)
        if (this.isMobile) {
            this.setupMobileControls();
        }

        // UI
        this.createUI();
        this.createDebugOverlay();
        this.createGyroDomButton();
        this.createRecalibrateDomButton();

        // Effet neige
        this.createSnow();

        // Musique
        this.setupMusic();

        // Volume SFX initial
        this.registry.set('sfxVolume', this.sfxVolume);

        // Générer quelques obstacles et cadeaux de test
        this.spawnTestObjects();

        console.log(`GameScene créée - Mode: ${this.isMobile ? 'Mobile' : 'PC'}`);
    }

    /**
     * Crée le background qui défile
     */
    private createBackground(levelWidth: number): void {
        const width = this.cameras.main.width;
        const height = this.cameras.main.height;

        // Background temporaire (sera remplacé par une vraie image)
        const graphics = this.add.graphics();

        // Ciel dégradé
        graphics.fillGradientStyle(0x87CEEB, 0x87CEEB, 0xE0F6FF, 0xE0F6FF, 1);
        graphics.fillRect(0, 0, width, height);

        // Nuages simples
        graphics.fillStyle(0xFFFFFF, 0.6);
        for (let i = 0; i < 5; i++) {
            const x = (width / 5) * i + 50;
            const y = 100 + Math.random() * 100;
            graphics.fillCircle(x, y, 30);
            graphics.fillCircle(x + 20, y, 25);
            graphics.fillCircle(x + 40, y, 30);
        }

        graphics.generateTexture('sky', width, height);
        graphics.destroy();

        this.background = this.add.tileSprite(0, 0, levelWidth, height, 'sky');
        this.background.setOrigin(0, 0);
        this.background.setScrollFactor(0.3); // Effet parallaxe
    }

    /**
     * Crée les plateformes du niveau (version étendue avec beaucoup plus de plateformes)
     */
    private createPlatforms(): void {
        this.platforms = this.physics.add.staticGroup();

        const height = this.cameras.main.height;

        // Sol principal (très large pour tout le niveau jusqu'à la cage + 400px)
        // Utiliser TileSprite pour répéter le motif sur toute la longueur
        const groundWidth = 10500; // Jusqu'à x=10500 (cage à 10100 + 400px)

        // Sol avec sprite répété (sol_150.png)
        const ground = this.add.tileSprite(groundWidth / 2, height - 25, groundWidth, 50, 'ground_tile');
        this.physics.add.existing(ground, true);
        (ground as any).setData?.('isGround', true);
        this.platforms.add(ground);
        this.platformRects.push({ x: groundWidth / 2, y: height - 25, w: groundWidth, h: 50 });

        // BEAUCOUP plus de plateformes réparties sur toute la longueur
        const platformPositions = [
            // Zone 1 (début - facile)
            { x: 400, y: height - 150, w: 200, h: 30 },
            { x: 700, y: height - 250, w: 180, h: 30 },
            { x: 1000, y: height - 200, w: 200, h: 30 },
            { x: 1300, y: height - 300, w: 150, h: 30 },

            // Zone 2 (moyen)
            { x: 1600, y: height - 180, w: 220, h: 30 },
            { x: 1900, y: height - 320, w: 160, h: 30 },
            { x: 2200, y: height - 240, w: 200, h: 30 },
            { x: 2500, y: height - 380, w: 140, h: 30 },
            { x: 2800, y: height - 280, w: 180, h: 30 },

            // Zone 3 (plus difficile)
            { x: 3100, y: height - 200, w: 150, h: 30 },
            { x: 3350, y: height - 350, w: 120, h: 30 },
            { x: 3600, y: height - 250, w: 200, h: 30 },
            { x: 3900, y: height - 400, w: 150, h: 30 },
            { x: 4200, y: height - 300, w: 180, h: 30 },

            // Zone 4 (avancé)
            { x: 4500, y: height - 180, w: 160, h: 30 },
            { x: 4800, y: height - 340, w: 140, h: 30 },
            { x: 5100, y: height - 250, w: 200, h: 30 },
            { x: 5400, y: height - 420, w: 150, h: 30 },
            { x: 5700, y: height - 320, w: 180, h: 30 },

            // Zone 5 (très difficile)
            { x: 6000, y: height - 200, w: 140, h: 30 },
            { x: 6250, y: height - 380, w: 120, h: 30 },
            { x: 6500, y: height - 280, w: 160, h: 30 },
            { x: 6800, y: height - 450, w: 130, h: 30 },
            { x: 7100, y: height - 350, w: 180, h: 30 },

            // Zone 6 (finale avant coffre)
            { x: 7400, y: height - 250, w: 200, h: 30 },
            { x: 7700, y: height - 180, w: 300, h: 30 }, // Grande plateforme pour coffre

            // Zone 7 (après le coffre - vers la cage du chien) +2500px
            { x: 8000, y: height - 200, w: 180, h: 30 },
            { x: 8300, y: height - 320, w: 160, h: 30 },
            { x: 8600, y: height - 240, w: 200, h: 30 },
            { x: 8900, y: height - 380, w: 140, h: 30 },
            { x: 9200, y: height - 280, w: 180, h: 30 },
            { x: 9500, y: height - 400, w: 150, h: 30 },
            { x: 9800, y: height - 200, w: 220, h: 30 },
            // Grande plateforme finale pour la cage - prolongée jusqu'à la fin (2600px de long)
            { x: 9900, y: height - 150, w: 2600, h: 30 }
        ];

        platformPositions.forEach((pos) => {
            // Choisir le meilleur sprite selon la largeur de la plateforme
            const spriteKey = this.choosePlatformSprite(pos.w);

            // Créer un TileSprite qui répète automatiquement le motif
            const platform = this.add.tileSprite(pos.x, pos.y, pos.w, pos.h, spriteKey);
            this.physics.add.existing(platform, true);
            this.platforms!.add(platform);
            this.platformRects.push({ x: pos.x, y: pos.y, w: pos.w, h: pos.h });
        });

        console.log(`${platformPositions.length} plateformes créées sur ${groundWidth}px`);
    }

    /**
     * Choisit le meilleur sprite de plateforme selon la largeur
     * Stratégie : utiliser le sprite le plus proche de la largeur demandée
     */
    private choosePlatformSprite(width: number): string {
        // Largeurs des sprites disponibles
        const sprites = [
            { key: 'platform_40', width: 40 },
            { key: 'platform_73', width: 73 },
            { key: 'platform_130', width: 130 },
            { key: 'platform_140', width: 140 },
            { key: 'platform_179', width: 179 }
        ];

        // Pour les très grandes plateformes (>200px), toujours utiliser le plus grand
        if (width >= 200) {
            return 'platform_179';
        }

        // Pour les petites/moyennes, choisir le sprite le plus proche
        // qui divise bien la largeur totale (pour éviter les coupures bizarres)
        let bestSprite = sprites[sprites.length - 1]; // Par défaut, le plus grand
        let bestScore = Infinity;

        for (const sprite of sprites) {
            // Calculer combien de fois le sprite rentre dans la largeur
            const repetitions = width / sprite.width;
            const remainder = width % sprite.width;

            // Score = reste (on préfère un reste petit) + pénalité si trop de répétitions
            const score = remainder + Math.abs(repetitions - Math.round(repetitions)) * 10;

            if (score < bestScore) {
                bestScore = score;
                bestSprite = sprite;
            }
        }

        return bestSprite.key;
    }

    /**
     * Crée les groupes d'obstacles, cadeaux et super trésors
     */
    private createObjectGroups(): void {
        this.obstacles = this.physics.add.group();
        this.gifts = this.physics.add.group();
        this.superTreasures = this.physics.add.group();

        // Collisions
        this.physics.add.overlap(this.player!, this.gifts, this.collectGift, undefined, this);
        this.physics.add.overlap(this.player!, this.obstacles, this.hitObstacle, undefined, this);
        this.physics.add.overlap(this.player!, this.superTreasures, this.collectSuperTreasure, undefined, this);
    }

    /**
     * Génère BEAUCOUP d'objets répartis sur tout le niveau
     */
    private spawnTestObjects(): void {
        const height = this.cameras.main.height;
        const minObjectSpacing = 120;
        const reservedPositions: Array<{ x: number; y: number; radius: number }> = [];
        const reserve = (x: number, y: number, radius: number): void => {
            reservedPositions.push({ x, y, radius });
        };
        const isTooClose = (x: number, y: number): boolean =>
            reservedPositions.some((pos) => {
                const distance = Phaser.Math.Distance.Between(x, y, pos.x, pos.y);
                return distance < minObjectSpacing + pos.radius;
            });
        let obstacleCount = 0;
        const targetObstacleCount = MIN_MUSHROOMS;
        const obstacleCandidates: Array<{ x: number; y: number }> = [];
        const addCandidate = (x: number, y: number): void => {
            obstacleCandidates.push({ x, y });
        };

        // SUPER TRESORS (rares et precieux - 1 par zone)
        const superTreasurePositions = [
            { x: 1000, y: height - 350 },  // Zone 1 - en hauteur
            { x: 2500, y: height - 420 },  // Zone 2 - tres haut
            { x: 3900, y: height - 450 },  // Zone 3 - tres haut
            { x: 5400, y: height - 470 },  // Zone 4 - ultra haut
            { x: 6800, y: height - 500 },  // Zone 5 - ultra haut
            { x: 7300, y: height - 250 },  // Zone 6 - sur plateforme finale
        ];
        // Coffre posé sur la plateforme à height - 180 (hauteur plateforme = 30px)
        const chestPosition = { x: 7700, y: height - 180 - 50 }; // -50 pour être bien au-dessus de la plateforme

        superTreasurePositions.forEach((pos) => reserve(pos.x, pos.y, 40));
        reserve(chestPosition.x, chestPosition.y, 60);

        // BEAUCOUP de cadeaux répartis partout (environ tous les 300-500px)
        const giftPositions = [
            // Zone 1
            600, 900, 1200, 1500,
            // Zone 2
            1800, 2100, 2400, 2700,
            // Zone 3
            3000, 3300, 3600, 3900,
            // Zone 4
            4200, 4500, 4800, 5100,
            // Zone 5
            5400, 5700, 6000, 6300,
            // Zone 6
            6600, 6900, 7200, 7500,
            // Zone 7 (après le coffre - vers la cage)
            8000, 8300, 8600, 8900, 9200, 9500, 9800, 10100,
        ];

        giftPositions.forEach((x) => {
            // Alterner entre sol et en hauteur
            const isHigh = Math.random() > 0.5;
            const y = isHigh ? height - 200 - Math.random() * 150 : height - 100;

            // Utiliser le sprite de cadeau (gift_40.png = 40x40px)
            const gift = this.add.image(x, y, 'gift_sprite');
            gift.setScale(1); // Garder la taille native (40x40)
            this.physics.add.existing(gift);
            this.gifts!.add(gift);
            reserve(x, y, 25);
        });

        // BEAUCOUP d'obstacles répartis partout
        const obstaclePositions = [
            // Zone 1
            800, 1100, 1400,
            // Zone 2
            2000, 2300, 2600, 2900,
            // Zone 3
            3200, 3500, 3800, 4100,
            // Zone 4
            4400, 4700, 5000, 5300,
            // Zone 5
            5600, 5900, 6200, 6500,
            // Zone 6
            6800, 7100, 7400,
            // Zone 7 (après le coffre - vers la cage) - PAS de champignons près de la cage
            8100, 8400, 8700, 9000,
        ];

        // Obstacles sur plateformes (x, y)
        const obstaclePlatforms = [
            { x: 700, y: height - 280 },
            { x: 1300, y: height - 330 },
            { x: 1900, y: height - 350 },
            { x: 2500, y: height - 410 },
            { x: 3350, y: height - 380 },
            { x: 3900, y: height - 430 },
            { x: 4800, y: height - 360 },
            { x: 5400, y: height - 440 },
            { x: 6250, y: height - 400 },
            { x: 6800, y: height - 500 },
        ];

        // Ajouter quelques champignons directement sur les plateformes existantes
        const platformPlaced: Array<{ x: number; y: number }> = [];
        this.platformRects
            .filter((rect) => rect.y < height - 80 && rect.w >= 120) // ignorer le sol et les très petites plateformes
            .forEach((rect) => {
                const x = rect.x + Phaser.Math.Between(Math.round(-rect.w / 4), Math.round(rect.w / 4));
                const y = rect.y - rect.h / 2;
                platformPlaced.push({ x, y });
            });

        obstaclePositions.forEach((x) => addCandidate(x, height - 50));

        obstaclePlatforms.forEach((pos) => {
            const target = this.platformRects.find((rect) => Math.abs(pos.x - rect.x) <= rect.w / 2);
            const topY = target ? target.y - target.h / 2 : pos.y;
            addCandidate(pos.x, topY);
        });

        platformPlaced.forEach((pos) => addCandidate(pos.x, pos.y));

        Phaser.Utils.Array.Shuffle(obstacleCandidates);

        obstacleCandidates.forEach((pos) => {
            if (obstacleCount >= targetObstacleCount) return;
            if (isTooClose(pos.x, pos.y)) return;

            const obstacle = this.physics.add.sprite(pos.x, pos.y, 'obstacle_mushroom');
            obstacle.setOrigin(0.5, 1);
            obstacle.setImmovable(true);
            obstacle.setPushable(false);
            obstacle.setScale(0.9);

            const body = obstacle.body as Phaser.Physics.Arcade.Body;
            body.setAllowGravity(false);
            body.setSize(45, 81);
            body.setOffset((obstacle.displayWidth - 45) / 2, obstacle.displayHeight - 81);

            this.obstacles!.add(obstacle);
            obstacleCount += 1;
            reserve(pos.x, pos.y, 50);
        });

        if (obstacleCount < targetObstacleCount) {
            console.warn(
                `⚠️ Champignons insuffisants: ${obstacleCount}/${targetObstacleCount}. ` +
                'Augmentez les positions candidates ou reduisez le minObjectSpacing.'
            );
        }

        superTreasurePositions.forEach((pos) => {
            const superTreasure = new SuperTreasure(this, pos.x, pos.y);
            this.superTreasures!.add(superTreasure);
        });

        // COFFRE FINAL au bout du niveau
        this.treasureChest = new TreasureChest(this, chestPosition.x, chestPosition.y, CHEST_REQUIRED_GIFTS);
        this.physics.add.overlap(this.player!, this.treasureChest, this.openChest, undefined, this);

        // CAGE avec le chien à la toute fin
        this.cage = new Cage(this, 10100, height - 150);

        console.log(`${giftPositions.length} cadeaux, ${obstaclePositions.length} obstacles, ${superTreasurePositions.length} SUPER TRÉSORS, 1 COFFRE FINAL et 1 CAGE créés`);
    }

    /**
     * Débloque l'audio sur iOS (requis après interaction utilisateur)
     */
    private unlockAudio(): void {
        // Sur iOS, l'audio doit être activé après une interaction utilisateur
        const soundManager = this.sound as Phaser.Sound.WebAudioSoundManager;

        if (soundManager.context) {
            // Si le contexte est suspendu, le reprendre
            if (soundManager.context.state === 'suspended') {
                soundManager.context.resume().then(() => {
                    console.log('[GameScene Audio] ✅ Context audio débloqué pour iOS');
                }).catch((error: any) => {
                    console.error('[GameScene Audio] ❌ Erreur déblocage audio:', error);
                });
            }
        }
    }

    /**
     * Configure les contrôles mobile
     */
    private setupMobileControls(): void {
        // Gyroscope
        this.gyroControl = new GyroControl();

        // Bouton de saut
        this.jumpButton = new JumpButton(this, () => {
            // IMPORTANT: Débloquer l'audio sur iOS lors de l'interaction
            this.unlockAudio();
            this.player?.jump();
        });

        // Boutons gauche/droite (en bas à gauche)
        this.directionalButtons = new DirectionalButtons(this);
    }

    /**
     * Crée l'interface utilisateur
     */
    private createUI(): void {
        // Score
        this.scoreText = this.add.text(20, 20, 'Score: 0', {
            fontSize: '32px',
            color: '#ffffff',
            stroke: '#000000',
            strokeThickness: 4,
        });
        this.scoreText.setScrollFactor(0);
        this.scoreText.setDepth(100);

        // Vies
        this.livesText = this.add.text(20, 60, `❤️ Vies: ${this.lives}`, {
            fontSize: '28px',
            color: '#ff0000',
            stroke: '#000000',
            strokeThickness: 4,
        });
        this.livesText.setScrollFactor(0);
        this.livesText.setDepth(100);

        // Cadeaux collectés
        this.giftsCollectedText = this.add.text(20, 100, `🎁 Cadeaux: ${this.giftsCollected}/${CHEST_REQUIRED_GIFTS}`, {
            fontSize: '24px',
            color: '#FFD700',
            stroke: '#000000',
            strokeThickness: 3,
        });
        this.giftsCollectedText.setScrollFactor(0);
        this.giftsCollectedText.setDepth(100);

        // Timer
        this.timerText = this.add.text(this.cameras.main.width / 2, 20, '3:00', {
            fontSize: '32px',
            color: '#ffffff',
            stroke: '#000000',
            strokeThickness: 4,
        });
        this.timerText.setOrigin(0.5, 0);
        this.timerText.setScrollFactor(0);
        this.timerText.setDepth(100);

        // Info contrôles (avec mention du double saut)
        const controlText = this.isMobile
            ? 'Inclinez pour bouger • Bouton pour sauter (DOUBLE SAUT disponible!)'
            : 'Flèches pour bouger • Espace pour sauter (DOUBLE SAUT disponible!)';

        this.controlInfoText = this.add.text(
            this.cameras.main.width / 2,
            this.cameras.main.height - 30,
            controlText,
            {
                fontSize: '18px',
                color: '#ffffff',
                backgroundColor: '#00000088',
                padding: { x: 10, y: 5 },
            }
        );
        this.controlInfoText.setOrigin(0.5);
        this.controlInfoText.setScrollFactor(0);
        this.controlInfoText.setDepth(100);

        // Bouton retour menu
        const backButton = this.add.text(this.cameras.main.width - 20, 20, '⬅ Menu', {
            fontSize: '24px',
            color: '#ffffff',
            backgroundColor: '#000000',
            padding: { x: 10, y: 5 },
        });
        backButton.setOrigin(1, 0);
        backButton.setScrollFactor(0);
        backButton.setDepth(100);
        backButton.setInteractive({ useHandCursor: true });
        backButton.on('pointerdown', () => {
            // IMPORTANT: Débloquer l'audio sur iOS
            this.unlockAudio();
            this.cleanup();
            this.scene.start('MenuScene');
        });

        // Volume musique
        this.volumeText = this.add.text(this.cameras.main.width - 20, 60, this.getVolumeLabel(), {
            fontSize: '18px',
            color: '#ffffff',
            backgroundColor: '#000000',
            padding: { x: 8, y: 4 },
        });
        this.volumeText.setOrigin(1, 0);
        this.volumeText.setScrollFactor(0);
        this.volumeText.setDepth(100);
        this.volumeText.setInteractive({ useHandCursor: true });
        this.volumeText.on('pointerdown', () => {
            // IMPORTANT: Débloquer l'audio sur iOS
            this.unlockAudio();
            this.cycleMusicVolume();
        });

        // Volume SFX
        this.sfxVolumeText = this.add.text(this.cameras.main.width - 20, 90, this.getSfxVolumeLabel(), {
            fontSize: '18px',
            color: '#ffffff',
            backgroundColor: '#000000',
            padding: { x: 8, y: 4 },
        });
        this.sfxVolumeText.setOrigin(1, 0);
        this.sfxVolumeText.setScrollFactor(0);
        this.sfxVolumeText.setDepth(100);
        this.sfxVolumeText.setInteractive({ useHandCursor: true });
        this.sfxVolumeText.on('pointerdown', () => {
            // IMPORTANT: Débloquer l'audio sur iOS
            this.unlockAudio();
            this.cycleSfxVolume();
        });
    }

    private createDebugOverlay(): void {
        if (!this.isMobile) return;

        this.debugText = this.add.text(10, 130, '', {
            fontSize: '12px',
            color: '#ffffff',
            backgroundColor: '#000000',
            padding: { x: 6, y: 6 },
        });
        this.debugText.setOrigin(0, 0);
        this.debugText.setScrollFactor(0);
        this.debugText.setDepth(200);

        this.gyroDebugButton = this.add.text(10, 70, 'Autoriser gyroscope', {
            fontSize: '12px',
            color: '#00ff00',
            backgroundColor: '#000000',
            padding: { x: 6, y: 4 },
        });
        this.gyroDebugButton.setOrigin(0, 0);
        this.gyroDebugButton.setScrollFactor(0);
        this.gyroDebugButton.setDepth(200);
        this.gyroDebugButton.setInteractive({ useHandCursor: true });
        this.gyroDebugButton.on('pointerdown', () => {
            // IMPORTANT: Débloquer l'audio sur iOS
            this.unlockAudio();
            this.requestGyroPermission();
        });
    }

    private createGyroDomButton(): void {
        if (!this.isMobile || this.gyroDomButton) return;

        const button = document.createElement('button');
        button.textContent = 'Autoriser gyroscope';
        button.style.position = 'fixed';
        button.style.right = '8px';
        button.style.top = '8px';
        button.style.zIndex = '9999';
        button.style.padding = '6px 10px';
        button.style.fontSize = '12px';
        button.style.background = '#000000';
        button.style.color = '#00ff00';
        button.style.border = '1px solid #00ff00';
        button.style.borderRadius = '4px';
        button.style.cursor = 'pointer';
        button.style.opacity = '0.9';
        button.addEventListener('click', () => {
            this.requestGyroPermission();
        });

        document.body.appendChild(button);
        this.gyroDomButton = button;

        this.events.once('shutdown', () => {
            this.removeGyroDomButton();
        });
        this.events.once('destroy', () => {
            this.removeGyroDomButton();
        });
    }

    private removeGyroDomButton(): void {
        if (!this.gyroDomButton) return;
        this.gyroDomButton.remove();
        this.gyroDomButton = undefined;
    }

    private createRecalibrateDomButton(): void {
        if (!this.isMobile || this.recalibrateDomButton) return;

        // Détecter iOS
        const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) ||
                     (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);

        // Bouton de recalibration uniquement sur iOS
        if (!isIOS) return;

        const button = document.createElement('button');
        button.textContent = '🔄 Recalibrer';
        button.style.position = 'fixed';
        button.style.right = '8px';
        button.style.top = '48px'; // En dessous du bouton gyroscope
        button.style.zIndex = '9999';
        button.style.padding = '8px 12px';
        button.style.fontSize = '14px';
        button.style.background = '#FF9500';
        button.style.color = '#ffffff';
        button.style.border = '2px solid #ffffff';
        button.style.borderRadius = '6px';
        button.style.cursor = 'pointer';
        button.style.opacity = '0.95';
        button.style.fontWeight = 'bold';
        button.addEventListener('click', () => {
            this.recalibrateGyroscope();
        });

        document.body.appendChild(button);
        this.recalibrateDomButton = button;

        this.events.once('shutdown', () => {
            this.removeRecalibrateDomButton();
        });
        this.events.once('destroy', () => {
            this.removeRecalibrateDomButton();
        });
    }

    private removeRecalibrateDomButton(): void {
        if (!this.recalibrateDomButton) return;
        this.recalibrateDomButton.remove();
        this.recalibrateDomButton = undefined;
    }

    private recalibrateGyroscope(): void {
        if (!this.gyroControl) return;

        // Afficher un message temporaire
        const message = document.createElement('div');
        message.textContent = '📱 Maintenez le téléphone en position neutre...';
        message.style.position = 'fixed';
        message.style.top = '50%';
        message.style.left = '50%';
        message.style.transform = 'translate(-50%, -50%)';
        message.style.zIndex = '10000';
        message.style.padding = '20px 30px';
        message.style.fontSize = '18px';
        message.style.background = 'rgba(0, 0, 0, 0.9)';
        message.style.color = '#ffffff';
        message.style.border = '3px solid #FF9500';
        message.style.borderRadius = '12px';
        message.style.fontWeight = 'bold';
        message.style.textAlign = 'center';
        document.body.appendChild(message);

        // Recalibrer après un court délai (laisser le temps à l'utilisateur de voir le message)
        setTimeout(() => {
            this.gyroControl?.calibrate();
            message.textContent = '✅ Calibration en cours...';

            // Retirer le message après 3 secondes (temps de calibration: 20 échantillons)
            setTimeout(() => {
                message.remove();
            }, 3000);
        }, 1000);
    }

    private showInitialCalibrationMessage(): void {
        const message = document.createElement('div');
        message.innerHTML = '📱 <strong>Calibration automatique</strong><br><br>Maintenez le téléphone en position neutre pendant 2 secondes...<br><br><small>Utilisez le bouton "🔄 Recalibrer" pour réinitialiser si besoin</small>';
        message.style.position = 'fixed';
        message.style.top = '50%';
        message.style.left = '50%';
        message.style.transform = 'translate(-50%, -50%)';
        message.style.zIndex = '10000';
        message.style.padding = '25px 35px';
        message.style.fontSize = '16px';
        message.style.background = 'rgba(0, 0, 0, 0.95)';
        message.style.color = '#ffffff';
        message.style.border = '3px solid #4CAF50';
        message.style.borderRadius = '12px';
        message.style.fontWeight = 'normal';
        message.style.textAlign = 'center';
        message.style.lineHeight = '1.5';
        document.body.appendChild(message);

        // Retirer le message après 4 secondes
        setTimeout(() => {
            message.remove();
        }, 4000);
    }

    private async requestGyroPermission(): Promise<void> {
        const hasDeviceOrientation =
            typeof window.DeviceOrientationEvent !== 'undefined';
        const requestOrientationPermission =
            (window.DeviceOrientationEvent as any)?.requestPermission;
        const requestMotionPermission =
            (window.DeviceMotionEvent as any)?.requestPermission;
        const isIOS = /iP(ad|hone|od)/.test(navigator.userAgent);
        const userActivation = (navigator as any).userActivation;

        if (isIOS && !window.isSecureContext) {
            this.registry.set('gyroPermission', 'blocked');
            return;
        }

        if (hasDeviceOrientation && typeof requestOrientationPermission === 'function') {
            try {
                const orientationStatus = await requestOrientationPermission.call(
                    window.DeviceOrientationEvent
                );
                let motionStatus = 'granted';
                if (typeof requestMotionPermission === 'function') {
                    motionStatus = await requestMotionPermission.call(
                        window.DeviceMotionEvent
                    );
                }

                if (orientationStatus === 'granted' && motionStatus === 'granted') {
                    this.registry.set('gyroPermission', 'granted');
                    this.removeGyroDomButton();

                    // Afficher un message de calibration pour iOS
                    if (isIOS) {
                        this.showInitialCalibrationMessage();
                    }
                    return;
                }

                const permState =
                    orientationStatus === 'granted' || motionStatus === 'granted'
                        ? 'partial'
                        : 'denied';
                this.registry.set('gyroPermission', permState);
                this.registry.set(
                    'gyroPermissionError',
                    `activation ${userActivation?.isActive}/${userActivation?.hasBeenActive}`
                );
                return;
            } catch (error) {
                const errorText =
                    error instanceof Error ? error.message : String(error);
                this.registry.set('gyroPermission', 'error');
                this.registry.set(
                    'gyroPermissionError',
                    `${errorText} (activation ${userActivation?.isActive}/${userActivation?.hasBeenActive})`
                );
                return;
            }
        }

        this.registry.set('gyroPermission', 'not-required');
    }

    update(time: number): void {
        if (!this.player) return;

        // Mise à jour du timer
        this.updateTimer(time);

        // Gestion des contrôles
        let direction = 0;

        // PC/Laptop : Clavier (priorité absolue)
        if (!this.isMobile && this.cursors) {
            if (this.cursors.left.isDown) {
                direction = -1;
                if (time % 1000 < 16) console.log('⬅️ Left pressed');
            } else if (this.cursors.right.isDown) {
                direction = 1;
                if (time % 1000 < 16) console.log('➡️ Right pressed');
            }

            // Saut avec Espace
            if (Phaser.Input.Keyboard.JustDown(this.cursors.space!)) {
                console.log('🚀 Space pressed - Jump!');
                this.player.jump();
            }

            // Saut avec flèche haut (alternative)
            if (Phaser.Input.Keyboard.JustDown(this.cursors.up!)) {
                console.log('⬆️ Up pressed - Jump!');
                this.player.jump();
            }
        } else if (!this.isMobile) {
            // Debug: pourquoi le clavier ne fonctionne pas?
            if (time % 2000 < 16) {
                console.log('[GameScene] ⚠️ Keyboard disabled: isMobile=', this.isMobile, 'cursors=', !!this.cursors);
            }
        }

        // Mobile/Tablette : boutons directionnels priment, sinon gyroscope
        if (this.isMobile) {
            // Vérifier d'abord les boutons directionnels (priorité)
            const dirButtons = this.directionalButtons?.getDirection() ?? 0;
            if (dirButtons !== 0) {
                direction = dirButtons;
            } else if (this.gyroControl) {
                // Sinon utiliser le gyroscope
                const tiltValue = this.gyroControl.getTiltValue();
                direction = tiltValue; // -1 à 1
            }
        }

        // Debug overlay (throttled)
        if (this.debugText && this.gyroControl && time - this.lastDebugUpdate > 500) {
            const info = this.gyroControl.getDebugInfo();
            const now = Date.now();
            const lastEventMs =
                info.lastEventAt > 0 ? Math.round(now - info.lastEventAt) : -1;
            const permState = this.registry.get('gyroPermission') || 'unknown';
            const permError = this.registry.get('gyroPermissionError') || '';

            // Déterminer quel axe est utilisé actuellement
            const axisUsed = info.useAlpha ? 'ALPHA' : (info.useGamma ? 'GAMMA' : 'BETA');

            this.debugText.setText(
                [
                    `perm: ${permState}`,
                    permError ? `err: ${permError}` : '',
                    `platform: ${info.platform}`,
                    `gyro active: ${info.active}`,
                    `--- AXES (raw values) ---`,
                    `ALPHA: ${info.alpha.toFixed(1)}° (boussole/Z)`,
                    `BETA: ${info.beta.toFixed(1)}° (avant/arrière/X)`,
                    `GAMMA: ${info.gamma.toFixed(1)}° (gauche/droite/Y)`,
                    `--- CONTROL ---`,
                    `Axe utilisé: ${axisUsed}`,
                    `tilt normalized: ${info.tilt.toFixed(2)}`,
                    `orientation: ${info.angle}°`,
                    `last event: ${lastEventMs}ms`,
                ]
                    .filter((line) => line !== '')
                    .join('\n')
            );
            this.lastDebugUpdate = time;
        }

        if (this.gyroDomButton && this.registry.get('gyroPermission') === 'granted') {
            this.removeGyroDomButton();
        }

        // Déplacer le joueur
        this.player.move(direction);
        this.player.update();

        // Système de checkpoint (sauvegarde tous les 1000px)
        const playerX = this.player.x;
        if (playerX > this.lastCheckpointX + 1000) {
            this.lastCheckpointX = Math.floor(playerX / 1000) * 1000;
            console.log(`✅ Checkpoint atteint à x=${this.lastCheckpointX}`);

            // Feedback visuel rapide
            this.cameras.main.flash(50, 0, 255, 0, true);
        }

        // Scroll du background (effet parallaxe)
        if (this.background) {
            this.background.tilePositionX = this.cameras.main.scrollX * 0.3;
        }

        // Vérifier la proximité avec le coffre pour afficher le message si pas assez de cadeaux
        if (this.treasureChest && !this.treasureChest.getIsOpen()) {
            const distanceToChest = Phaser.Math.Distance.Between(
                this.player.x,
                this.player.y,
                7700, // Position X du coffre
                this.cameras.main.height - 180 // Position Y du coffre
            );

            // Si proche du coffre (moins de 150px) et pas assez de cadeaux, afficher le message
            if (distanceToChest < 150 && this.giftsCollected < CHEST_REQUIRED_GIFTS) {
                this.treasureChest.showRequirementText();
            } else {
                this.treasureChest.hideRequirementText();
            }
        }

        // Mise à jour du chien dans la cage
        if (this.cage) {
            this.cage.update();

            // Vérifier si le joueur est près de la cage avec la clé
            if (this.hasKey && !this.cage.isOpened()) {
                const distance = Phaser.Math.Distance.Between(
                    this.player.x,
                    this.player.y,
                    10100, // Position X de la cage
                    this.cameras.main.height - 150 // Position Y de la cage
                );

                // Si le joueur est assez proche (moins de 100px)
                if (distance < 100) {
                    this.openCageAndCompleteLevel();
                }
            }
        }
    }

    /**
     * Met à jour le timer
     */
    private updateTimer(time: number): void {
        const elapsed = Math.floor((time - this.gameStartTime) / 1000);
        this.timeRemaining = LEVEL_DURATION - elapsed;

        if (this.timeRemaining <= 0) {
            this.timeRemaining = 0;
            this.endGame();
        }

        const minutes = Math.floor(this.timeRemaining / 60);
        const seconds = this.timeRemaining % 60;
        this.timerText?.setText(`${minutes}:${seconds.toString().padStart(2, '0')}`);

        // Changement de couleur si temps faible
        if (this.timeRemaining <= 30) {
            this.timerText?.setColor('#FF0000');
        }
    }

    /**
     * Collecte un cadeau
     */
    private collectGift(_player: any, gift: any): void {
        gift.destroy();
        this.giftsCollected++;
        this.addScore(100);
        this.playSfx('sfx_powerup', 0.5);

        // Mettre à jour l'UI
        this.giftsCollectedText?.setText(`🎁 Cadeaux: ${this.giftsCollected}/${CHEST_REQUIRED_GIFTS}`);

        // Feedback si on a assez pour le coffre
        if (this.giftsCollected >= CHEST_REQUIRED_GIFTS && !this.treasureChest?.getIsOpen()) {
            // Flash doré
            this.cameras.main.flash(100, 255, 215, 0, true);

            const hint = this.add.text(
                this.cameras.main.scrollX + this.cameras.main.width / 2,
                this.cameras.main.height / 2,
                '🏆 Assez de cadeaux! Trouvez le coffre! 🏆',
                {
                    fontSize: '32px',
                    color: '#FFD700',
                    stroke: '#000000',
                    strokeThickness: 4,
                }
            );
            hint.setOrigin(0.5);
            hint.setScrollFactor(0);
            hint.setDepth(1000);

            this.tweens.add({
                targets: hint,
                alpha: 0,
                duration: 3000,
                onComplete: () => hint.destroy(),
            });
        }
    }

    /**
     * Collision avec un obstacle
     */
    private hitObstacle(player: any, obstacle: any): void {
        // Vérifier si on saute dessus (player au-dessus de l'obstacle)
        const playerBody = player.body as Phaser.Physics.Arcade.Body;
        const obstacleBody = obstacle.body as Phaser.Physics.Arcade.Body;

        const isJumpingOn = playerBody.velocity.y > 0 &&
                            playerBody.bottom <= obstacleBody.top + 10;

        if (isJumpingOn) {
            // Sauter dessus = détruit l'obstacle
            obstacle.destroy();
            this.addScore(50); // Bonus pour avoir sauté dessus
            player.jump(); // Petit rebond
            this.playSfx('sfx_saute_champi', 0.6);

            // Effet visuel
            const explosion = this.add.circle(obstacleBody.x, obstacleBody.y, 20, 0x00FF00, 0.5);
            explosion.setDepth(100);
            this.tweens.add({
                targets: explosion,
                scaleX: 2,
                scaleY: 2,
                alpha: 0,
                duration: 300,
                onComplete: () => explosion.destroy(),
            });

            console.log('💚 Obstacle détruit en sautant dessus ! +50 pts');
        } else {
            // Collision frontale = perd une vie
            if (player.getIsInvincible()) {
                console.log('🛡️ Invincible - pas de dégâts');
                return;
            }

            this.playSfx('sfx_hit', 0.6);
            this.loseLife();
        }
    }

    /**
     * Collecte un SUPER TRÉSOR (beaucoup de points!)
     */
    private collectSuperTreasure(_player: any, superTreasure: any): void {
        // Effet visuel de collecte
        this.cameras.main.flash(200, 255, 215, 0, true); // Flash doré

        // Destruction avec effet
        superTreasure.destroy();

        // GROS BONUS de points!
        this.addScore(500);
        this.playSfx('sfx_super', 0.6);

        // BONUS DE TEMPS : +10 secondes // # modifer par codex + ancien code: // BONUS DE TEMPS : +5 secondes
        const bonusSeconds = 10; // # modifer par codex + ancien code: (aucun)
        this.gameStartTime += bonusSeconds * 1000; // # modifer par codex + ancien code: this.gameStartTime -= bonusSeconds * 1000;
        this.timeRemaining += bonusSeconds; // # modifer par codex + ancien code: this.timeRemaining += 5;
        this.updateTimer(this.time.now); // # modifer par codex + ancien code: (aucun)
        console.log('⏱️ Super Trésor : +10 secondes ! Temps restant:', this.timeRemaining); // # modifer par codex + ancien code: console.log('⏱️ Super Trésor : +5 secondes ! Temps restant:', this.timeRemaining);

        // Message spécial
        const bonusText = this.add.text(
            this.cameras.main.scrollX + this.cameras.main.width / 2,
            this.cameras.main.height / 2,
            '★ SUPER TRÉSOR +500 ★\n⏱️ +10 SECONDES ⏱️', // # modifer par codex + ancien code: '★ SUPER TRÉSOR +500 ★\n⏱️ +5 SECONDES ⏱️',
            {
                fontSize: '48px',
                color: '#FFD700',
                stroke: '#FF8C00',
                strokeThickness: 6,
                fontStyle: 'bold',
                align: 'center',
            }
        );
        bonusText.setOrigin(0.5);
        bonusText.setScrollFactor(0);
        bonusText.setDepth(1000);

        // Animation du texte (apparition puis disparition)
        this.tweens.add({
            targets: bonusText,
            scaleX: 1.5,
            scaleY: 1.5,
            alpha: 0,
            duration: 1500,
            ease: 'Power2',
            onComplete: () => {
                bonusText.destroy();
            },
        });

        console.log('🌟 SUPER TRÉSOR COLLECTÉ ! +500 points !');
    }

    /**
     * Ouvre le coffre au trésor final et donne la clé
     */
    private openChest(_player: any, chest: any): void {
        if (chest.canOpen(this.giftsCollected)) {
            const result = chest.open(this);
            this.addScore(result.bonus);

            // Donner la clé au joueur avec animation
            if (result.hasKey) {
                this.hasKey = true;
                console.log('🗝️ Clé obtenue ! Direction la cage du chien !');

                // Créer une clé animée qui vole vers le joueur
                this.createKeyPickupAnimation();
            }

            // Ne PAS terminer le niveau ici - continuer vers la cage
        } else if (!chest.getIsOpen()) {
            // Pas assez de cadeaux
            const remaining = chest.getRequiredGifts() - this.giftsCollected;

            const warning = this.add.text(
                this.cameras.main.scrollX + this.cameras.main.width / 2,
                this.cameras.main.height / 2,
                `❌ Encore ${remaining} cadeaux nécessaires! ❌`,
                {
                    fontSize: '28px',
                    color: '#FF0000',
                    stroke: '#000000',
                    strokeThickness: 4,
                }
            );
            warning.setOrigin(0.5);
            warning.setScrollFactor(0);
            warning.setDepth(1000);

            this.tweens.add({
                targets: warning,
                alpha: 0,
                duration: 2000,
                onComplete: () => warning.destroy(),
            });
        }
    }

    /**
     * Animation de récupération de la clé
     */
    private createKeyPickupAnimation(): void {
        // Créer une grosse icône de clé au centre de l'écran
        const keyIcon = this.add.text(
            this.cameras.main.scrollX + this.cameras.main.width / 2,
            this.cameras.main.height / 2,
            '🗝️',
            {
                fontSize: '120px',
            }
        );
        keyIcon.setOrigin(0.5);
        keyIcon.setScrollFactor(0);
        keyIcon.setDepth(10000); // Augmenté pour être au-dessus de tout (neige = 2000)
        keyIcon.setAlpha(0);
        keyIcon.setScale(0.1);

        // Message "Clé obtenue"
        const keyText = this.add.text(
            this.cameras.main.scrollX + this.cameras.main.width / 2,
            this.cameras.main.height / 2 + 100,
            '🗝️ CLÉ OBTENUE ! 🗝️\nDirection : Cage du chien →',
            {
                fontSize: '40px', // Augmenté pour être plus visible
                color: '#FFD700',
                stroke: '#000000',
                strokeThickness: 8, // Augmenté pour meilleure visibilité
                fontStyle: 'bold',
                align: 'center',
            }
        );
        keyText.setOrigin(0.5);
        keyText.setScrollFactor(0);
        keyText.setDepth(10000); // Augmenté pour être au-dessus de tout (neige = 2000)
        keyText.setAlpha(0);

        // Animation de la clé : apparition avec rotation
        this.tweens.add({
            targets: keyIcon,
            scale: 1.5,
            alpha: 1,
            angle: 360,
            duration: 800,
            ease: 'Back.easeOut',
        });

        // Animation du texte : apparition
        this.tweens.add({
            targets: keyText,
            alpha: 1,
            duration: 600,
            delay: 400,
            ease: 'Power2',
        });

        // Après 2 secondes, faire disparaître tout
        this.time.delayedCall(2500, () => {
            this.tweens.add({
                targets: [keyIcon, keyText],
                alpha: 0,
                scale: 0.5,
                duration: 500,
                ease: 'Power2',
                onComplete: () => {
                    keyIcon.destroy();
                    keyText.destroy();
                },
            });
        });

        // Flash doré pour attirer l'attention
        this.cameras.main.flash(300, 255, 215, 0, true);

        // Son (si disponible)
        this.playSfx('sfx_powerup', 0.7);
    }

    /**
     * Ouvre la cage avec la clé et termine le niveau
     */
    private openCageAndCompleteLevel(): void {
        if (!this.cage || this.cage.isOpened()) return;

        console.log('🗝️ Ouverture de la cage avec la clé !');

        // Ouvrir la cage
        this.cage.open();

        // Jouer la musique du chien libéré
        this.playSfx('sfx_chien', 0.7);

        // Message de libération
        const liberationText = this.add.text(
            this.cameras.main.scrollX + this.cameras.main.width / 2,
            this.cameras.main.height / 2 - 100,
            '🐕 CHIEN LIBÉRÉ ! 🐕\n🎉 NIVEAU TERMINÉ ! 🎉',
            {
                fontSize: '48px',
                color: '#FFD700',
                stroke: '#FF4500',
                strokeThickness: 8,
                fontStyle: 'bold',
                align: 'center',
            }
        );
        liberationText.setOrigin(0.5);
        liberationText.setScrollFactor(0);
        liberationText.setDepth(2000);

        // Flash de victoire
        this.cameras.main.flash(500, 255, 215, 0, true);

        // Animation du texte
        this.tweens.add({
            targets: liberationText,
            scaleX: 1.3,
            scaleY: 1.3,
            alpha: 0,
            duration: 3000,
            ease: 'Power2',
            onComplete: () => {
                liberationText.destroy();
            },
        });

        // Après 3 secondes, terminer le niveau
        this.time.delayedCall(3000, () => {
            this.levelComplete();
        });
    }

    /**
     * Animation de victoire - Niveau terminé !
     */
    private levelComplete(): void {
        console.log('🏆 NIVEAU TERMINÉ ! VICTOIRE !');

        // Arrêter la physique
        this.physics.pause();
        this.playSfx('sfx_levelcomplete', 0.6);

        // Flash doré géant
        this.cameras.main.flash(1000, 255, 215, 0, true);

        // Fond sombre semi-transparent
        const overlay = this.add.rectangle(
            this.cameras.main.scrollX + this.cameras.main.width / 2,
            this.cameras.main.height / 2,
            this.cameras.main.width,
            this.cameras.main.height,
            0x000000,
            0.7
        );
        overlay.setScrollFactor(0);
        overlay.setDepth(1500);

        // Message VICTOIRE
        const victoryText = this.add.text(
            this.cameras.main.scrollX + this.cameras.main.width / 2,
            this.cameras.main.height / 2 - 150,
            '🏆 NIVEAU TERMINÉ ! 🏆',
            {
                fontSize: '64px',
                color: '#FFD700',
                stroke: '#FF8C00',
                strokeThickness: 10,
                fontStyle: 'bold',
            }
        );
        victoryText.setOrigin(0.5);
        victoryText.setScrollFactor(0);
        victoryText.setDepth(2000);

        // Animation pulsation
        this.tweens.add({
            targets: victoryText,
            scaleX: 1.2,
            scaleY: 1.2,
            duration: 800,
            yoyo: true,
            repeat: -1,
            ease: 'Sine.easeInOut',
        });

        // Statistiques
        const stats = this.add.text(
            this.cameras.main.scrollX + this.cameras.main.width / 2,
            this.cameras.main.height / 2 - 20,
            `Score Final: ${this.score}\n\n` +
            `Cadeaux collectés: ${this.giftsCollected}\n` +
            `Vies restantes: ${this.lives}\n\n` +
            `Félicitations !`,
            {
                fontSize: '32px',
                color: '#FFFFFF',
                stroke: '#000000',
                strokeThickness: 6,
                align: 'center',
                lineSpacing: 10,
            }
        );
        stats.setOrigin(0.5);
        stats.setScrollFactor(0);
        stats.setDepth(2000);

        // Message vidéo de fin
        const returnText = this.add.text(
            this.cameras.main.scrollX + this.cameras.main.width / 2,
            this.cameras.main.height - 80,
            'Vidéo de fin dans 5 secondes...',
            {
                fontSize: '24px',
                color: '#CCCCCC',
                stroke: '#000000',
                strokeThickness: 4,
            }
        );
        returnText.setOrigin(0.5);
        returnText.setScrollFactor(0);
        returnText.setDepth(2000);

        // Particules de célébration
        this.createVictoryParticles();

        // Lancer la vidéo de fin après 5 secondes
        this.time.delayedCall(5000, () => {
            this.cleanup();
            this.scene.start('EndScene');
        });
    }

    /**
     * Crée des particules de célébration pour la victoire
     */
    private createVictoryParticles(): void {
        const centerX = this.cameras.main.scrollX + this.cameras.main.width / 2;

        // Créer 50 particules dorées qui explosent
        for (let i = 0; i < 50; i++) {
            const angle = (i / 50) * Math.PI * 2;
            const radius = 100 + Math.random() * 200;

            const particle = this.add.circle(
                centerX,
                this.cameras.main.height / 2,
                5 + Math.random() * 10,
                Math.random() > 0.5 ? 0xFFD700 : 0xFF8C00
            );
            particle.setScrollFactor(0);
            particle.setDepth(1900);

            this.tweens.add({
                targets: particle,
                x: centerX + Math.cos(angle) * radius,
                y: this.cameras.main.height / 2 + Math.sin(angle) * radius - 100,
                alpha: 0,
                scaleX: 0.2,
                scaleY: 0.2,
                duration: 2000 + Math.random() * 1000,
                ease: 'Power2',
                onComplete: () => {
                    particle.destroy();
                },
            });
        }
    }

    /**
     * Fait perdre une vie au joueur
     */
    private loseLife(): void {
        this.lives--;
        this.livesText?.setText(`❤️ Vies: ${this.lives}`);

        // Flash rouge
        this.cameras.main.flash(200, 255, 0, 0, true);
        this.cameras.main.shake(200, 0.01);

        console.log(`💔 Vie perdue! Vies restantes: ${this.lives}`);

        if (this.lives <= 0) {
            this.gameOver();
        } else {
            this.respawnPlayer();
        }
    }

    /**
     * Réapparaît au dernier checkpoint avec invincibilité
     */
    private respawnPlayer(): void {
        if (!this.player) return;

        // Téléporter au dernier checkpoint
        this.player.setPosition(this.lastCheckpointX, this.cameras.main.height - 200);
        this.player.setVelocity(0, 0);

        // Activer l'invincibilité
        this.player.makeInvincible(this);

        // Message
        const respawnText = this.add.text(
            this.cameras.main.scrollX + this.cameras.main.width / 2,
            this.cameras.main.height / 2,
            `💫 RÉAPPARITION! ${this.lives} ❤️ restantes`,
            {
                fontSize: '36px',
                color: '#00FF00',
                stroke: '#000000',
                strokeThickness: 6,
            }
        );
        respawnText.setOrigin(0.5);
        respawnText.setScrollFactor(0);
        respawnText.setDepth(1000);

        this.tweens.add({
            targets: respawnText,
            alpha: 0,
            duration: 2000,
            onComplete: () => respawnText.destroy(),
        });
    }

    /**
     * Game Over - plus de vies
     */
    private gameOver(): void {
        console.log('💀 GAME OVER');

        // Arrêter la physique
        this.physics.pause();
        this.playSfx('sfx_gameover', 0.6);

        // Écran de game over
        const gameOverText = this.add.text(
            this.cameras.main.scrollX + this.cameras.main.width / 2,
            this.cameras.main.height / 2 - 50,
            'GAME OVER',
            {
                fontSize: '72px',
                color: '#FF0000',
                stroke: '#000000',
                strokeThickness: 8,
                fontStyle: 'bold',
            }
        );
        gameOverText.setOrigin(0.5);
        gameOverText.setScrollFactor(0);
        gameOverText.setDepth(2000);

        const scoreText = this.add.text(
            this.cameras.main.scrollX + this.cameras.main.width / 2,
            this.cameras.main.height / 2 + 50,
            `Score Final: ${this.score}`,
            {
                fontSize: '36px',
                color: '#FFFFFF',
                stroke: '#000000',
                strokeThickness: 4,
            }
        );
        scoreText.setOrigin(0.5);
        scoreText.setScrollFactor(0);
        scoreText.setDepth(2000);

        // Retour au menu après 3 secondes
        this.time.delayedCall(3000, () => {
            this.cleanup();
            this.scene.start('MenuScene');
        });
    }

    /**
     * Ajoute des points au score
     */
    private addScore(points: number): void {
        this.score += points;
        if (this.score < 0) this.score = 0;
        this.scoreText?.setText(`Score: ${this.score}`);
    }

    /**
     * Termine le jeu
     */
    private endGame(): void {
        console.log(`Jeu terminé ! Score final: ${this.score}`);

        // TODO: Créer une EndScene
        this.add.text(
            this.cameras.main.width / 2,
            this.cameras.main.height / 2,
            `TEMPS ÉCOULÉ!\nScore: ${this.score}`,
            {
                fontSize: '48px',
                color: '#ffffff',
                backgroundColor: '#000000',
                padding: { x: 20, y: 20 },
                align: 'center',
            }
        ).setOrigin(0.5).setScrollFactor(0).setDepth(1000);

        this.time.delayedCall(3000, () => {
            this.cleanup();
            this.scene.start('MenuScene');
        });
    }

    /**
     * Configure et lance la musique de fond
     */
    private setupMusic(): void {
        if (this.bgMusic && this.bgMusic.isPlaying) {
            return;
        }

        this.bgMusic = this.sound.add('bgm', {
            loop: true,
            volume: this.musicVolume,
        });
        this.bgMusic.play();
    }

    /**
     * Met à jour le volume musique (cycle 0%, 20%, 40%, 60%, 80%, 100%)
     */
    private cycleMusicVolume(): void {
        const steps = [0, 0.2, 0.4, 0.6, 0.8, 1];
        const currentIndex = steps.findIndex((v) => v === this.musicVolume);
        const nextIndex = (currentIndex + 1) % steps.length;
        this.musicVolume = steps[nextIndex];

        if (this.bgMusic) {
            const webAudio = this.bgMusic as Phaser.Sound.WebAudioSound;
            const htmlAudio = this.bgMusic as Phaser.Sound.HTML5AudioSound;
            if (typeof webAudio.setVolume === 'function') {
                webAudio.setVolume(this.musicVolume);
            } else if (typeof htmlAudio.setVolume === 'function') {
                htmlAudio.setVolume(this.musicVolume);
            }
            if (this.musicVolume === 0 && this.bgMusic.isPlaying) {
                this.bgMusic.pause();
            } else if (this.musicVolume > 0 && this.bgMusic.isPaused) {
                this.bgMusic.resume();
            } else if (this.musicVolume > 0 && !this.bgMusic.isPlaying) {
                this.bgMusic.play();
            }
        }

        this.volumeText?.setText(this.getVolumeLabel());
    }

    private getVolumeLabel(): string {
        return `🔊 Volume: ${Math.round(this.musicVolume * 100)}% (clic)`;
    }

    /**
     * Met à jour le volume des SFX (cycle 0%, 20%, 40%, 60%, 80%, 100%)
     */
    private cycleSfxVolume(): void {
        const steps = [0, 0.2, 0.4, 0.6, 0.8, 1];
        const currentIndex = steps.findIndex((v) => v === this.sfxVolume);
        const nextIndex = (currentIndex + 1) % steps.length;
        this.sfxVolume = steps[nextIndex];
        this.registry.set('sfxVolume', this.sfxVolume);
        this.sfxVolumeText?.setText(this.getSfxVolumeLabel());
    }

    private getSfxVolumeLabel(): string {
        return `🎚️ Bruitages: ${Math.round(this.sfxVolume * 100)}% (clic)`;
    }

    /**
     * Lecture SFX avec volume global appliqué
     */
    private playSfx(key: string, baseVolume: number = 0.5): void {
        const globalSfxVolume = (this.registry.get('sfxVolume') as number | undefined) ?? this.sfxVolume;
        // Vérifier que l'asset audio existe pour éviter un blocage si le fichier est absent
        const audioCache = this.cache.audio;
        if (!audioCache.exists(key)) {
            console.warn(`SFX manquant: ${key}`);
            return;
        }
        this.sound.play(key, { volume: baseVolume * globalSfxVolume });
    }

    /**
     * Effet de neige qui tombe en overlay
     */
    private createSnow(): void {
        // Texture flocon si absente
        if (!this.textures.exists('snowflake')) {
            const g = this.add.graphics();
            g.fillStyle(0xffffff, 1);
            g.fillCircle(3, 3, 3);
            g.generateTexture('snowflake', 6, 6);
            g.destroy();
        }

        // Emetteur unique attaché à un manager en overlay
        const emitterManager = this.add.particles(0, 0, 'snowflake', {
            x: { min: 0, max: this.cameras.main.width },
            y: -10,
            lifespan: 8000,
            speedY: { min: 50, max: 100 },
            speedX: { min: -20, max: 20 },
            scale: { min: 0.5, max: 1 },
            quantity: 4,
            frequency: 80,
            alpha: { start: 0.9, end: 0.15 },
            rotate: { min: -30, max: 30 },
            blendMode: 'ADD',
            emitZone: { type: 'random', source: new Phaser.Geom.Rectangle(0, 0, this.cameras.main.width, 1) } as any,
        });
        emitterManager.setScrollFactor(0);
        emitterManager.setDepth(2000);

        // Neige qui s'accumule au sol (colonne par colonne)
        const initSnowBuffer = () => {
            const cols = Math.max(10, Math.ceil(this.cameras.main.width / 8));
            this.snowHeights = new Array(cols).fill(0);
            if (!this.snowPileGraphics) {
                this.snowPileGraphics = this.add.graphics();
                this.snowPileGraphics.setScrollFactor(0);
                this.snowPileGraphics.setDepth(5);
            }
            this.renderSnowPile();
        };

        initSnowBuffer();
        this.scale.on('resize', initSnowBuffer);

        const maxHeight = 160;
        this.snowPileTimer = this.time.addEvent({
            delay: 120,
            loop: true,
            callback: () => {
                if (this.snowHeights.length === 0) return;
                const idx = Phaser.Math.Between(0, this.snowHeights.length - 1);
                const add = Phaser.Math.Between(2, 6);
                this.snowHeights[idx] = Math.min(maxHeight, this.snowHeights[idx] + add);
                this.renderSnowPile();
            },
        });
    }

    /**
     * Dessine l'accumulation de neige au sol
     */
    private renderSnowPile(): void {
        if (!this.snowPileGraphics || this.snowHeights.length === 0) return;
        const gfx = this.snowPileGraphics;
        const colWidth = this.cameras.main.width / this.snowHeights.length;
        const baseY = this.cameras.main.height;

        gfx.clear();
        gfx.fillStyle(0xffffff, 0.9);

        this.snowHeights.forEach((h, i) => {
            if (h <= 0) return;
            const x = i * colWidth;
            gfx.fillRect(x, baseY - h, colWidth + 1, h);
        });
    }

    /**
     * Nettoyage avant de quitter la scène
     */
    private cleanup(): void {
        if (this.gyroControl) {
            this.gyroControl.destroy();
        }
        if (this.jumpButton) {
            this.jumpButton.destroy();
        }
        if (this.directionalButtons) {
            this.directionalButtons.destroy();
        }
        if (this.bgMusic) {
            this.bgMusic.stop();
            this.bgMusic.destroy();
        }
        if (this.snowPileTimer) {
            this.snowPileTimer.destroy();
        }
    }
}
