// renderEnemies.js : rendu des ennemis (sprites + barre de vie + ombre)
// pool de sprites reutilises (pas de recreate par frame)

import { Container, Graphics, Assets, Sprite } from 'pixi.js';
import { iso, getTh, getTw } from './renderer.js';
import { ENEMY_HITBOX_RADIUS } from './constants.js';

let _debugHitboxes = false;
export function setDebugHitboxes(v) { _debugHitboxes = v; }

// Assets Fracture
const _ft = {};
let _fractureReady = false;

export async function loadFractureAssets() {
    if (_fractureReady) return;
    const b = '../assets/sprites/fracture/';

    function anim(prefix, dirs, n, folder) {
        const out = [];
        for (const d of dirs) {
            for (let i = 0; i < n; i++) {
                const pad = String(i).padStart(3, '0');
                out.push([`${prefix}_${d}_${i}`, `${b}animations/${folder}/${d}/frame_${pad}.png`]);
            }
        }
        return out;
    }

    const D4 = ['south', 'north', 'east', 'west'];
    const entries = [
        ['f_south', b + 'rotations/south.png'],
        ['f_north', b + 'rotations/north.png'],
        ['f_east',  b + 'rotations/east.png'],
        ['f_west',  b + 'rotations/west.png'],
        ...anim('frun', D4, 4, 'running'),
    ];

    for (const [key, path] of entries) {
        const tex = await Assets.load(path);
        tex.source.scaleMode = 'nearest';
        _ft[key] = tex;
    }
    _fractureReady = true;
}

// Assets Rampant
const _rt = {};
let _rampantReady = false;

export async function loadRampantAssets() {
    if (_rampantReady) return;
    const b = '../assets/sprites/rampant/';

    function anim(prefix, dirs, n, folder) {
        const out = [];
        for (const d of dirs) {
            for (let i = 0; i < n; i++) {
                const pad = String(i).padStart(3, '0');
                out.push([`${prefix}_${d}_${i}`, `${b}animations/${folder}/${d}/frame_${pad}.png`]);
            }
        }
        return out;
    }

    const D4 = ['south', 'north', 'east', 'west'];
    const entries = [
        ['r_south', b + 'rotations/south.png'],
        ['r_north', b + 'rotations/north.png'],
        ['r_east',  b + 'rotations/east.png'],
        ['r_west',  b + 'rotations/west.png'],
        ...anim('rrun', D4, 6, 'running'),
    ];

    for (const [key, path] of entries) {
        const tex = await Assets.load(path);
        tex.source.scaleMode = 'nearest';
        _rt[key] = tex;
    }
    _rampantReady = true;
}

// Assets Colosse
const _ct = {};
let _colosseReady = false;

export async function loadColosseAssets() {
    if (_colosseReady) return;
    const b = '../assets/sprites/colosse/';
    function anim(prefix, dirs, n, folder) {
        const out = [];
        for (const d of dirs) {
            for (let i = 0; i < n; i++) {
                const pad = String(i).padStart(3, '0');
                out.push([`${prefix}_${d}_${i}`, `${b}animations/${folder}/${d}/frame_${pad}.png`]);
            }
        }
        return out;
    }
    const D4 = ['south', 'north', 'east', 'west'];
    const entries = [
        ['c_south', b + 'rotations/south.png'],
        ['c_north', b + 'rotations/north.png'],
        ['c_east',  b + 'rotations/east.png'],
        ['c_west',  b + 'rotations/west.png'],
        ...anim('crun', D4, 6, 'running'),
    ];
    for (const [key, path] of entries) {
        const tex = await Assets.load(path);
        tex.source.scaleMode = 'nearest';
        _ct[key] = tex;
    }
    _colosseReady = true;
}

// Assets Éclat
const _et = {};
let _eclatReady = false;

export async function loadEclatAssets() {
    if (_eclatReady) return;
    const b = '../assets/sprites/eclat/';
    function anim(prefix, dirs, n, folder) {
        const out = [];
        for (const d of dirs) {
            for (let i = 0; i < n; i++) {
                const pad = String(i).padStart(3, '0');
                out.push([`${prefix}_${d}_${i}`, `${b}animations/${folder}/${d}/frame_${pad}.png`]);
            }
        }
        return out;
    }
    const D4 = ['south', 'north', 'east', 'west'];
    const entries = [
        ['e_south', b + 'rotations/south.png'],
        ['e_north', b + 'rotations/north.png'],
        ['e_east',  b + 'rotations/east.png'],
        ['e_west',  b + 'rotations/west.png'],
        ...anim('erun', D4, 8, 'running'),
    ];
    for (const [key, path] of entries) {
        const tex = await Assets.load(path);
        tex.source.scaleMode = 'nearest';
        _et[key] = tex;
    }
    _eclatReady = true;
}

// Assets Vexaris
const _vt = {};
let _vexarisReady = false;

export async function loadVexarisAssets() {
    if (_vexarisReady) return;
    const b = '../assets/sprites/vexaris/';
    function anim(prefix, dirs, n, folder) {
        const out = [];
        for (const d of dirs) {
            for (let i = 0; i < n; i++) {
                const pad = String(i).padStart(3, '0');
                out.push([`${prefix}_${d}_${i}`, `${b}animations/${folder}/${d}/frame_${pad}.png`]);
            }
        }
        return out;
    }
    const D4 = ['south', 'north', 'east', 'west'];
    const entries = [
        ['v_south', b + 'rotations/south.png'],
        ['v_north', b + 'rotations/north.png'],
        ['v_east',  b + 'rotations/east.png'],
        ['v_west',  b + 'rotations/west.png'],
        ...anim('vrun', D4, 4, 'running'),
        ...anim('vatk', D4, 7, 'attack'),
        ...anim('vchg', D4, 7, 'charge'),
        ...anim('vbst', ['south'], 9, 'burst'),
    ];
    for (const [key, path] of entries) {
        const tex = await Assets.load(path);
        tex.source.scaleMode = 'nearest';
        _vt[key] = tex;
    }
    _vexarisReady = true;
}

// Animation state par ennemi (position précédente + état animation)
const _ePrevPos   = {};   // id → { x, y }
const _eAnimState = {};   // id → { facing, frame, timer, action }

const F_RUN_FPS  = 8;   const F_RUN_TICK = 1 / F_RUN_FPS;
const R_RUN_FPS  = 12;  const R_RUN_TICK = 1 / R_RUN_FPS;
const C_RUN_FPS  = 5;   const C_RUN_TICK = 1 / C_RUN_FPS;  // colosse très lent
const E_RUN_FPS  = 16;  const E_RUN_TICK = 1 / E_RUN_FPS;  // éclat ultrarapide
const V_RUN_FPS  = 8;   const V_RUN_TICK = 1 / V_RUN_FPS;  // running 4 frames
const V_ATK_FPS  = 10;  const V_ATK_TICK = 1 / V_ATK_FPS;  // attack  7 frames
const V_CHG_FPS  = 14;  const V_CHG_TICK = 1 / V_CHG_FPS;  // charge  7 frames
const V_BST_FPS  = 8;   const V_BST_TICK = 1 / V_BST_FPS;  // burst   9 frames south
const TICK_DT    = 0.05;
// iso()   = projection monde → pixels isométriques
// getTh() = pixels par unité monde (pour les tailles proportionnelles)


// Couleur de chaque type d'ennemi (valeur hexadécimale RGB)
const ENEMY_COLORS = {
    fracture: 0xcc3333,  // rouge foncé — ennemi de base qui fonce sur le Soulgate
    rampant:  0xff6600,  // orange — attaque les joueurs
    colosse:  0x882200,  // brun-rouge — lent et résistant
    eclat:    0xffcc00,  // jaune — petit et rapide
    vexaris:  0xaa22ff,  // violet — boss vague 2
    general:  0xcc6600,  // orange foncé — sous-boss invoqué par Morveth
    morveth:  0x550088,  // violet très foncé — boss final vague 3
};

// Tailles des ennemis selon le type
// min/max = limites en pixels (pour les petits et grands écrans)
// scale   = facteur multiplicateur de th (pixels par unité monde)
const ENEMY_SIZES = {
    morveth: { min: 14, max: 55, scale: 0.65 },  // boss final = très grand
    vexaris: { min: 12, max: 45, scale: 0.50 },  // boss vague 2 = grand
    general: { min: 8,  max: 30, scale: 0.32 },  // sous-boss = moyen
};
const DEFAULT_SIZE = { min: 6, max: 25, scale: 0.22 };
// Taille par défaut pour les ennemis normaux (fracture, rampant, colosse, eclat)


export function updateEnemies(layer, pool, enemies) {
    // Met à jour les sprites de tous les ennemis depuis les données serveur
    // layer   = Container PixiJS du layer "ennemis"
    // pool    = { id → Container } — sprites existants
    // enemies = tableau d'EnemyState reçus dans msg.enemies

    // 1. Supprimer les sprites des ennemis morts (plus dans la liste serveur)
    const ids = new Set(enemies.map(e => e.id));
    // ids = Set des IDs encore vivants ce tick

    for (const [id, container] of Object.entries(pool)) {
        if (!ids.has(id)) {
            layer.removeChild(container);
            delete pool[id];
            delete _ePrevPos[id];
            delete _eAnimState[id];
        }
    }

    // 2. Créer ou mettre à jour chaque ennemi
    for (const e of enemies) {
        // e = objet ennemi : { id, type, x, y, hp, max_hp, is_boss, frozen }

        if (!pool[e.id]) {
            pool[e.id] = _createEnemyGraphic(e.type);
            layer.addChild(pool[e.id]);
            _ePrevPos[e.id]   = { x: e.x, y: e.y };
            _eAnimState[e.id] = { facing: 'south', frame: 0, timer: 0 };
        }

        const ctr  = pool[e.id];
        const pos  = iso(e.x, e.y);
        const prev = _ePrevPos[e.id];
        const anim = _eAnimState[e.id];

        // Détecter direction depuis le déplacement
        const ddx = e.x - prev.x;
        const ddy = e.y - prev.y;
        const moving = Math.abs(ddx) > 0.01 || Math.abs(ddy) > 0.01;
        if (moving) anim.facing = _enemyDir(ddx, ddy) ?? anim.facing;
        _ePrevPos[e.id] = { x: e.x, y: e.y };

        ctr.x = pos.x;
        ctr.y = pos.y;

        // Sprite Fracture
        if (e.type === 'fracture' && _fractureReady && ctr._sprite) {
            anim.timer += TICK_DT;
            if (anim.timer >= F_RUN_TICK) {
                anim.timer -= F_RUN_TICK;
                anim.frame = (anim.frame + 1) % 4;
            }
            ctr._sprite.texture = moving
                ? _ft[`frun_${anim.facing}_${anim.frame}`]
                : _ft[`f_${anim.facing}`];
        }

        // Sprite Rampant
        if (e.type === 'rampant' && _rampantReady && ctr._sprite) {
            anim.timer += TICK_DT;
            if (anim.timer >= R_RUN_TICK) {
                anim.timer -= R_RUN_TICK;
                anim.frame = (anim.frame + 1) % 6;
            }
            ctr._sprite.texture = moving
                ? _rt[`rrun_${anim.facing}_${anim.frame}`]
                : _rt[`r_${anim.facing}`];
        }

        // Sprite Colosse
        if (e.type === 'colosse' && _colosseReady && ctr._sprite) {
            anim.timer += TICK_DT;
            if (anim.timer >= C_RUN_TICK) {
                anim.timer -= C_RUN_TICK;
                anim.frame = (anim.frame + 1) % 6;
            }
            ctr._sprite.texture = moving
                ? _ct[`crun_${anim.facing}_${anim.frame}`]
                : _ct[`c_${anim.facing}`];
        }

        // Sprite Éclat
        if (e.type === 'eclat' && _eclatReady && ctr._sprite) {
            anim.timer += TICK_DT;
            if (anim.timer >= E_RUN_TICK) {
                anim.timer -= E_RUN_TICK;
                anim.frame = (anim.frame + 1) % 8;
            }
            ctr._sprite.texture = moving
                ? _et[`erun_${anim.facing}_${anim.frame}`]
                : _et[`e_${anim.facing}`];
        }

        // Sprite Vexaris
        if (e.type === 'vexaris' && _vexarisReady && ctr._sprite) {
            const prevAction = anim.action ?? 'idle';
            let action;
            if (e.is_charging) {
                action = 'charge';
            } else if (moving) {
                action = 'run';
            } else if (anim.action === 'burst' && anim.frame < 8) {
                action = 'burst'; // laisser le burst se terminer
            } else {
                action = 'attack';
            }
            if (action !== prevAction) { anim.frame = 0; anim.timer = 0; }
            anim.action = action;
            anim.timer += TICK_DT;

            if (action === 'charge') {
                if (anim.timer >= V_CHG_TICK) { anim.timer -= V_CHG_TICK; anim.frame = (anim.frame + 1) % 7; }
                ctr._sprite.texture = _vt[`vchg_${anim.facing}_${anim.frame}`];
            } else if (action === 'run') {
                if (anim.timer >= V_RUN_TICK) { anim.timer -= V_RUN_TICK; anim.frame = (anim.frame + 1) % 4; }
                ctr._sprite.texture = _vt[`vrun_${anim.facing}_${anim.frame}`];
            } else if (action === 'burst') {
                if (anim.timer >= V_BST_TICK) { anim.timer -= V_BST_TICK; anim.frame = Math.min(8, anim.frame + 1); }
                ctr._sprite.texture = _vt[`vbst_south_${anim.frame}`];
            } else {
                if (anim.timer >= V_ATK_TICK) { anim.timer -= V_ATK_TICK; anim.frame = (anim.frame + 1) % 7; }
                ctr._sprite.texture = _vt[`vatk_${anim.facing}_${anim.frame}`];
            }
        }

        ctr.tint = e.frozen ? 0x88bbff : 0xffffff;
        // Si gelé (sort divin Seris) → teinte bleue
        // Sinon → blanc = pas de teinte (couleur de base)
        // e.frozen = bool envoyé par le serveur (frozen_timer > 0)

        _updateHealthBar(ctr, e.hp, e.max_hp);

        // Debug : hitbox de collision
        if (ctr._hboxG) {
            const hg = ctr._hboxG;
            hg.clear();
            if (_debugHitboxes) {
                const rx = ENEMY_HITBOX_RADIUS * getTw() / 2;
                const ry = ENEMY_HITBOX_RADIUS * getTh() / 2;
                hg.ellipse(0, 0, rx, ry).stroke({ color: 0xff4400, width: 1.5, alpha: 0.9 });
            }
        }
    }
}


function _updateHealthBar(ctr, hp, maxHp) {
    // Met à jour la barre de vie d'un ennemi
    // ctr   = le Container de l'ennemi (contient barFg en tant que propriété custom)
    // hp    = points de vie actuels
    // maxHp = points de vie max

    const ratio = maxHp > 0 ? Math.max(0, hp / maxHp) : 0;
    // ratio = pourcentage de vie restante (0.0 à 1.0)
    // Math.max(0, ...) = éviter les valeurs négatives si hp < 0 (sécurité)
    // maxHp > 0 ? ... : 0 = éviter la division par zéro

    const barFg = ctr._barFg;
    // _barFg = la Graphics de la barre de vie (stockée comme propriété custom sur le Container)
    // Le _ devant = convention "propriété interne"

    if (!barFg) return;  // sécurité si le Container n'a pas été initialisé correctement

    barFg.clear();  // effacer le dessin précédent de la barre

    if (ratio > 0) {
        // Redessiner la barre avec la nouvelle largeur proportionnelle au ratio
        barFg.rect(ctr._barX, ctr._barY, ctr._barW * ratio, ctr._barH)
             .fill({ color: 0xff3333 });
        // ctr._barW * ratio = largeur totale × ratio HP → barre qui rétrécit
        // 0xff3333 = rouge
    }
    // Si ratio = 0 → on ne dessine rien (ennemi presque mort)
}


function _enemyDir(dx, dy) {
    if (Math.abs(dx) < 0.01 && Math.abs(dy) < 0.01) return null;
    if (Math.abs(dx) >= Math.abs(dy)) return dx > 0 ? 'east' : 'west';
    return dy > 0 ? 'south' : 'north';
}


function _createEnemyGraphic(type) {
    // Crée le Container PixiJS pour un ennemi (appelé une seule fois par ennemi)
    // type = string : "fracture", "rampant", "colosse", "eclat", "vexaris", "morveth", "general"

    const th = getTh();  // pixels par unité monde (pour les tailles proportionnelles)
    const container = new Container();

    // Calculer le rayon selon le type
    const sz = ENEMY_SIZES[type] ?? DEFAULT_SIZE;
    // ENEMY_SIZES[type] = taille spécifique si boss/général, sinon DEFAULT_SIZE
    // ?? = operateur nullish coalescing : si null ou undefined → utiliser DEFAULT_SIZE

    const r = Math.max(sz.min, Math.min(sz.max, th * sz.scale));
    // th * sz.scale = taille proportionnelle au zoom
    // Math.max(sz.min, Math.min(sz.max, ...)) = clamp entre min et max

    const color = ENEMY_COLORS[type] ?? 0xff0000;

    // Sprite Rampant
    // Canvas 48×48, char bbox y=[8..41], anchor y=0.75 → anchor canvas=36
    // Char top au-dessus de l'anchor = 36-8 = 28 canvas pixels
    // Scale = (th*1.4)/48 → char top à screen y = -28*(th*1.4/48) = -th*0.817
    if (type === 'rampant' && _rampantReady) {
        const shadow = new Graphics();
        shadow.ellipse(0, r * 0.4, r * 0.5, r * 0.12).fill({ color: 0x000000, alpha: 0.3 });
        const scale  = (th * 1.4) / 48;
        const sprite = new Sprite(_rt.r_south);
        sprite.anchor.set(0.5, 0.75);
        sprite.scale.set(scale);

        const barW  = th * 0.7;
        const barH  = Math.max(2, th * 0.035);
        const barY  = -(th * 0.82 + barH + 8);   // 8px marge au-dessus de la tête
        const barBg = new Graphics();
        barBg.rect(-barW / 2, barY, barW, barH).fill({ color: 0x220000 });
        const barFg = new Graphics();
        barFg.rect(-barW / 2, barY, barW, barH).fill({ color: 0xff3333 });
        const hboxG = new Graphics();
        container.addChild(shadow, sprite, barBg, barFg, hboxG);
        container._sprite = sprite;
        container._barFg  = barFg;
        container._barX   = -barW / 2;
        container._barY   = barY;
        container._barW   = barW;
        container._barH   = barH;
        container._hboxG  = hboxG;
        return container;
    }

    // Sprite Fracture
    // Canvas 68×68, char bbox y=[10..58], anchor y=0.75 → anchor canvas=51
    // Char top au-dessus de l'anchor = 51-10 = 41 canvas pixels
    // Scale = (th*1.2)/48 → char top à screen y = -41*(th*1.2/48) = -th*1.025
    if (type === 'fracture' && _fractureReady) {
        const shadow = new Graphics();
        shadow.ellipse(0, r * 0.5, r * 0.6, r * 0.15).fill({ color: 0x000000, alpha: 0.3 });
        const scale  = (th * 1.2) / 48;
        const sprite = new Sprite(_ft.f_south);
        sprite.anchor.set(0.5, 0.75);
        sprite.scale.set(scale);

        const barW  = th * 0.8;
        const barH  = Math.max(2, th * 0.04);
        const barY  = -(th * 1.025 + barH + 10);   // 10px marge au-dessus de la tête
        const barBg = new Graphics();
        barBg.rect(-barW / 2, barY, barW, barH).fill({ color: 0x220000 });
        const barFg = new Graphics();
        barFg.rect(-barW / 2, barY, barW, barH).fill({ color: 0xff3333 });
        const hboxG = new Graphics();
        container.addChild(shadow, sprite, barBg, barFg, hboxG);
        container._sprite = sprite;
        container._barFg  = barFg;
        container._barX   = -barW / 2;
        container._barY   = barY;
        container._barW   = barW;
        container._barH   = barH;
        container._hboxG  = hboxG;
        return container;
    }

    // Sprite Colosse
    // Canvas 92×92, char top à y=13, anchor y=0.75 → anchor=69, dist=56px
    // Scale = (th*2.0)/92 → char_top = -56*(th*2.0/92) = -th*1.217
    if (type === 'colosse' && _colosseReady) {
        const shadow = new Graphics();
        shadow.ellipse(0, r * 0.6, r * 0.9, r * 0.22).fill({ color: 0x000000, alpha: 0.35 });
        const scale  = (th * 2.0) / 92;
        const sprite = new Sprite(_ct.c_south);
        sprite.anchor.set(0.5, 0.75);
        sprite.scale.set(scale);
        const barW  = th * 1.2;
        const barH  = Math.max(2, th * 0.05);
        const barY  = -(th * 1.22 + barH + 10);
        const barBg = new Graphics();
        barBg.rect(-barW / 2, barY, barW, barH).fill({ color: 0x220000 });
        const barFg = new Graphics();
        barFg.rect(-barW / 2, barY, barW, barH).fill({ color: 0xff3333 });
        const hboxG = new Graphics();
        container.addChild(shadow, sprite, barBg, barFg, hboxG);
        container._sprite = sprite;
        container._barFg  = barFg;
        container._barX   = -barW / 2;
        container._barY   = barY;
        container._barW   = barW;
        container._barH   = barH;
        container._hboxG  = hboxG;
        return container;
    }

    // Sprite Vexaris
    // Canvas 92×92, char top à y≈12, anchor y=0.75 → anchor=69, dist=57px
    // Scale = (th*2.2)/92 → char_top = -57*(th*2.2/92) = -th*1.363
    if (type === 'vexaris' && _vexarisReady) {
        const shadow = new Graphics();
        shadow.ellipse(0, r * 0.7, r * 1.1, r * 0.28).fill({ color: 0x330033, alpha: 0.45 });
        const scale  = (th * 2.2) / 92;
        const sprite = new Sprite(_vt.v_south);
        sprite.anchor.set(0.5, 0.75);
        sprite.scale.set(scale);
        const barW  = th * 1.6;
        const barH  = Math.max(3, th * 0.06);
        const barY  = -(th * 1.36 + barH + 12);
        const barBg = new Graphics();
        barBg.rect(-barW / 2, barY, barW, barH).fill({ color: 0x220022 });
        const barFg = new Graphics();
        barFg.rect(-barW / 2, barY, barW, barH).fill({ color: 0xaa22ff });
        const hboxG = new Graphics();
        container.addChild(shadow, sprite, barBg, barFg, hboxG);
        container._sprite = sprite;
        container._barFg  = barFg;
        container._barX   = -barW / 2;
        container._barY   = barY;
        container._barW   = barW;
        container._barH   = barH;
        container._hboxG  = hboxG;
        return container;
    }

    // Sprite Éclat
    // Canvas 36×36, char top à y=4, anchor y=0.75 → anchor=27, dist=23px
    // Scale = (th*1.0)/36 → char_top = -23*(th/36) = -th*0.639
    if (type === 'eclat' && _eclatReady) {
        const shadow = new Graphics();
        shadow.ellipse(0, r * 0.3, r * 0.4, r * 0.10).fill({ color: 0x000000, alpha: 0.25 });
        const scale  = (th * 1.0) / 36;
        const sprite = new Sprite(_et.e_south);
        sprite.anchor.set(0.5, 0.75);
        sprite.scale.set(scale);
        const barW  = th * 0.5;
        const barH  = Math.max(2, th * 0.03);
        const barY  = -(th * 0.64 + barH + 6);
        const barBg = new Graphics();
        barBg.rect(-barW / 2, barY, barW, barH).fill({ color: 0x220000 });
        const barFg = new Graphics();
        barFg.rect(-barW / 2, barY, barW, barH).fill({ color: 0xff3333 });
        const hboxG = new Graphics();
        container.addChild(shadow, sprite, barBg, barFg, hboxG);
        container._sprite = sprite;
        container._barFg  = barFg;
        container._barX   = -barW / 2;
        container._barY   = barY;
        container._barW   = barW;
        container._barH   = barH;
        container._hboxG  = hboxG;
        return container;
    }

    const body = new Graphics();

    // Ombre au sol
    body.ellipse(0, r * 0.5, r * 0.7, r * 0.18).fill({ color: 0x000000, alpha: 0.25 });
    // Ellipse aplatie légèrement en dessous du centre (r*0.5) → simuler une ombre

    // Cercle principal de l'ennemi
    body.circle(0, 0, r).fill({ color });
    // Contour blanc subtil
    body.circle(0, 0, r).stroke({ color: 0xffffff, width: 1, alpha: 0.2 });

    // Barre de vie
    const barW = r * 2.4;  // largeur totale de la barre = légèrement plus large que le cercle
    const barH = Math.max(2, th * 0.04);  // hauteur de la barre (au moins 2px)
    const barY = -(r * 1.1 + barH + 3);  // position Y = au-dessus du cercle (négatif = vers le haut)

    const barBg = new Graphics();
    // Fond de la barre (rouge très foncé = barre vide)
    barBg.rect(-barW / 2, barY, barW, barH).fill({ color: 0x220000 });
    // rect(x, y, largeur, hauteur) — centré horizontalement (-barW/2)

    const barFg = new Graphics();
    // Remplissage de la barre (rouge vif = vie restante)
    // Dessiné à 100% au départ, puis mis à jour par _updateHealthBar()
    barFg.rect(-barW / 2, barY, barW, barH).fill({ color: 0xff3333 });

    const hboxG = new Graphics();

    container.addChild(body, barBg, barFg, hboxG);
    // Ordre d'ajout = ordre d'affichage (barFg par-dessus barBg par-dessus body)

    // Stocker les infos de la barre sur le Container pour les réutiliser dans _updateHealthBar
    // On les préfixe avec _ pour indiquer que c'est de l'état interne
    container._barFg = barFg;    // référence au Graphics à redessiner
    container._barX  = -barW / 2;  // X de départ de la barre
    container._barY  = barY;       // Y de la barre
    container._barW  = barW;       // largeur TOTALE (× ratio HP = largeur réelle)
    container._barH  = barH;       // hauteur de la barre
    container._hboxG = hboxG;      // Graphics de la hitbox debug

    return container;
}
