import Phaser from 'phaser';
import { Director } from '../core/Director';
import { Audio } from '../core/Audio';
import { activateDay, applyTone, DChoiceOpt, DNode } from '../core/quests';

const FONT = '"PingFang SC","Microsoft YaHei","Hiragino Sans GB",sans-serif';
const EXPR: Record<string, number> = { smile: 0, flat: 1, off: 2 };

export class UIScene extends Phaser.Scene {
  busy = false;
  private dial!: Phaser.GameObjects.Graphics;
  private promptT!: Phaser.GameObjects.Text;
  private toastT!: Phaser.GameObjects.Text;
  // dialogue
  private box!: Phaser.GameObjects.Container;
  private nameT!: Phaser.GameObjects.Text;
  private bodyT!: Phaser.GameObjects.Text;
  private portrait!: Phaser.GameObjects.Image;
  private portraitBg!: Phaser.GameObjects.Graphics;
  private hintT!: Phaser.GameObjects.Text;
  private dq: DNode[] = [];
  private onDone?: () => void;
  private choice: DChoiceOpt[] | null = null;
  private choiceIdx = 0;
  private openAt = 0;
  // overlays
  private rainG!: Phaser.GameObjects.Graphics; private raining = false; private rainY = 0;
  private forcedC!: Phaser.GameObjects.Container; private forcedOn = false; private confetti: { x: number; y: number; c: number; s: number }[] = [];
  private dbg!: HTMLDivElement;
  private domKey!: (e: KeyboardEvent) => void;

  constructor() { super('UI'); }

  create() {
    this.busy = false;
    // dial
    this.dial = this.add.graphics().setDepth(1000).setScrollFactor(0);
    this.drawDial();
    // prompt + toast
    this.promptT = this.add.text(160, 116, '', { fontFamily: FONT, fontSize: '9px', color: '#fffbe9', backgroundColor: '#00000088', padding: { x: 3, y: 1 } }).setOrigin(0.5).setDepth(1000).setScrollFactor(0).setVisible(false);
    this.toastT = this.add.text(160, 14, '', { fontFamily: FONT, fontSize: '9px', color: '#fff2c0', backgroundColor: '#00000099', padding: { x: 4, y: 2 }, align: 'center', wordWrap: { width: 280 } }).setOrigin(0.5, 0).setDepth(1200).setScrollFactor(0).setAlpha(0);

    // dialogue box
    const bg = this.add.graphics();
    bg.fillStyle(0x2a2230, 0.94).fillRoundedRect(4, 128, 312, 48, 4);
    bg.lineStyle(1, 0xffd27a, 0.8).strokeRoundedRect(4, 128, 312, 48, 4);
    this.portraitBg = this.add.graphics();
    this.portraitBg.fillStyle(0x14100e, 1).fillRoundedRect(8, 132, 40, 40, 3);
    this.portrait = this.add.image(28, 152, 'portraits', 0).setScale(1.1);
    this.nameT = this.add.text(54, 133, '', { fontFamily: FONT, fontSize: '10px', color: '#ffd27a', fontStyle: 'bold' });
    this.bodyT = this.add.text(54, 148, '', { fontFamily: FONT, fontSize: '10px', color: '#fdf6e3', wordWrap: { width: 252 }, lineSpacing: 2 });
    this.hintT = this.add.text(308, 166, '▶', { fontFamily: FONT, fontSize: '9px', color: '#ffd27a' }).setOrigin(1, 0.5);
    this.box = this.add.container(0, 0, [bg, this.portraitBg, this.portrait, this.nameT, this.bodyT, this.hintT]).setDepth(900).setScrollFactor(0).setVisible(false);

    // overlays
    this.rainG = this.add.graphics().setDepth(800).setScrollFactor(0);
    this.forcedC = this.add.container(0, 0).setDepth(850).setScrollFactor(0).setVisible(false);
    const fbg = this.add.graphics(); fbg.fillStyle(0xff88bb, 0.10).fillRect(0, 0, 320, 180);
    const ftxt = this.add.text(160, 30, '※ 欢乐庆典 ※', { fontFamily: FONT, fontSize: '14px', color: '#ff5599', fontStyle: 'bold' }).setOrigin(0.5);
    this.forcedC.add([fbg, ftxt]);

    // input
    // 动作键走 DOM 监听（持久 UIScene 的 Phaser 键盘在初始场景下不可靠；DOM 与场景顺序无关）
    this.domKey = (e: KeyboardEvent) => {
      if (e.repeat) return;
      if (e.code === 'Backquote') { this.toggleDebug(); e.preventDefault(); return; }
      if (this.box.visible) {
        if (e.code === 'KeyE' || e.code === 'Enter' || e.code === 'Space') { this.tryAdvance(); e.preventDefault(); }
        else if (e.code === 'KeyW' || e.code === 'ArrowUp') this.moveChoice(-1);
        else if (e.code === 'KeyS' || e.code === 'ArrowDown') this.moveChoice(1);
      } else if (e.code === 'KeyE') {
        (this.scene.get('World') as any)?.tryInteract?.();
      }
    };
    window.addEventListener('keydown', this.domKey);
    this.input.on('pointerdown', () => { if (this.box.visible) this.tryAdvance(); });

    // Director listeners
    const redraw = () => this.drawDial();
    Director.on('change', redraw);
    Director.on('stage', redraw);
    Director.on('glitch', (t: string) => this.flashGlitch());
    Director.on('toast', (m: string) => this.toast(m));
    Director.on('dusk', () => { Audio.sfxBell(); this.toast('※ 黄昏钟声 ※ 天黑了……回小屋，睡一觉吧。'); });
    this.events.once('shutdown', () => { Director.off('change', redraw); Director.off('stage', redraw); this.dbg?.remove(); window.removeEventListener('keydown', this.domKey); });

    this.buildDebug();
  }

  // ---------------- sunflower dial (§6.1) ----------------
  private drawDial() {
    const g = this.dial; g.clear();
    const cx = 28, cy = 26, R = 12;
    g.fillStyle(0x3a2f22, 0.55).fillCircle(cx, cy, R + 6);
    const petals = Director.petals, s = Director.stage;
    for (let i = 0; i < 12; i++) {
      const a = (i / 12) * Math.PI * 2 - Math.PI / 2;
      const lit = i < petals;
      const col = lit ? (s >= 3 ? 0xfff3b4 : 0xffd257) : 0xcabf9a;
      g.fillStyle(col, lit ? 1 : 0.75).fillCircle(cx + Math.cos(a) * R, cy + Math.sin(a) * R, 3.3);
    }
    g.fillStyle(0xe8a44e, 1).fillCircle(cx, cy, 6.5);
    g.fillStyle(0x9a6a34, 1).fillCircle(cx, cy, 4.8);
    if (Director.blackSeeds) {
      for (const [dx, dy] of [[-2, -1], [1, -2], [2, 1], [-1, 2], [0, 0]]) g.fillStyle(0x241c1c, 1).fillCircle(cx + dx, cy + dy, 1.1);
    }
  }

  // ---------------- prompt / toast ----------------
  showPrompt(text: string | null) { this.promptT.setVisible(!!text && !this.busy).setText(text || ''); }
  toast(msg: string) {
    this.toastT.setText(msg).setAlpha(1);
    this.tweens.killTweensOf(this.toastT);
    this.tweens.add({ targets: this.toastT, alpha: 0, delay: 2400, duration: 700 });
  }

  // ---------------- dialogue ----------------
  showDialogue(nodes: DNode[], onDone?: () => void) {
    this.dq = nodes.slice(); this.onDone = onDone; this.choice = null; this.busy = true;
    this.box.setVisible(true); this.showPrompt(null); this.openAt = performance.now();
    this.next();
  }
  private next() {
    if (this.dq.length === 0) { this.close(); return; }
    const node = this.dq.shift()! as any;
    if (node.choice) this.renderChoice(node.choice);
    else this.renderLine(node);
  }
  private renderLine(l: any) {
    this.choice = null;
    const txt = l.raw ? l.text : Director.corrupt(l.text, l.speaker);
    const hasSpeaker = !!l.speaker || !!l.npcId;
    this.nameT.setText(l.npcId ? (nameOf(l.npcId)) : (l.speaker || ''));
    this.bodyT.setText(txt).setY(hasSpeaker ? 148 : 144);
    this.setPortrait(l.npcId);
    this.hintT.setText('▶');
    Audio.sfxBeep();
  }
  private renderChoice(opts: DChoiceOpt[]) {
    this.choice = opts; this.choiceIdx = 0;
    this.nameT.setText('你');
    this.setPortrait(undefined);
    this.hintT.setText('W/S 选择 · E 确定');
    this.drawChoices();
    Audio.sfxBeep();
  }
  private drawChoices() {
    if (!this.choice) return;
    const lines = this.choice.map((o, i) => (i === this.choiceIdx ? '▶ ' : '  ') + o.label);
    this.bodyT.setText(lines.join('\n')).setY(140);
  }
  private setPortrait(npcId?: string) {
    if (npcId) {
      const def = (Director as any);
      const expr = Director.npcExpression(npcId);
      const tex = spriteOf(npcId);
      this.portrait.setVisible(true).setTexture(tex, EXPR[expr]).setScale(1.5);
      this.portraitBg.setVisible(true);
    } else {
      // narration / player: 玩家永远微笑头像
      this.portrait.setVisible(true).setTexture('portraits', 0).setScale(1.1);
      this.portraitBg.setVisible(true);
    }
  }
  private tryAdvance() {
    if (!this.box.visible || performance.now() - this.openAt < 160) return;
    if (this.choice) { this.chooseCurrent(); return; }
    this.next();
  }
  private moveChoice(d: number) {
    if (!this.box.visible || !this.choice) return;
    this.choiceIdx = (this.choiceIdx + this.choice.length + d) % this.choice.length;
    this.drawChoices(); Audio.sfxBeep();
  }
  private chooseCurrent() {
    const opt = this.choice![this.choiceIdx];
    this.choice = null;
    applyTone(opt.tone);
    opt.effect?.();
    if (opt.then && opt.then.length) this.dq = [...opt.then, ...this.dq];
    this.next();
  }
  private close() {
    this.box.setVisible(false); this.busy = false;
    const cb = this.onDone; this.onDone = undefined; cb?.();
  }

  // ---------------- overlays ----------------
  setRain(on: boolean) { this.raining = on; if (!on) this.rainG.clear(); }
  setForced(on: boolean) { this.forcedOn = on; this.forcedC.setVisible(on); if (on && this.confetti.length === 0) for (let i = 0; i < 40; i++) this.confetti.push({ x: Math.random() * 320, y: Math.random() * 180, c: [0xff5599, 0xffd257, 0x66ccff, 0x88ee99][i % 4], s: 20 + Math.random() * 40 }); }
  flashGlitch() {
    const t = this.add.text(160, 90, 'PT-0▓', { fontFamily: 'monospace', fontSize: '18px', color: '#ff4444', backgroundColor: '#000000' }).setOrigin(0.5).setDepth(2000).setScrollFactor(0);
    let n = 0; const ev = this.time.addEvent({ delay: 40, repeat: 5, callback: () => { t.setX(160 + (Math.random() * 8 - 4)); t.setColor(n++ % 2 ? '#44ffee' : '#ff4444'); } });
    this.time.delayedCall(200, () => { t.destroy(); ev.remove(); });
  }
  playDream(prevDay: number, cb: () => void) {
    const c = this.add.container(0, 0).setDepth(2500).setScrollFactor(0);
    const bg = this.add.graphics(); bg.fillStyle(0x000000, 1).fillRect(0, 0, 320, 180); c.add(bg);
    const t = this.add.text(160, 90, '（睡着了……）', { fontFamily: FONT, fontSize: '11px', color: '#8a8a8a' }).setOrigin(0.5); c.add(t);
    const leak = prevDay >= 3 || Director.stage >= 3;
    const dur = leak ? (1000 + (Director.stage >= 4 ? 800 : 0)) : 0;
    this.time.delayedCall(700, () => {
      if (leak) {
        const w = this.add.graphics(); w.fillStyle(0xdfe2e6, 1).fillRect(0, 0, 320, 180);
        w.fillStyle(0xc2c6cc, 1).fillRect(40, 96, 90, 40); w.fillStyle(0x9aa0a8, 1).fillRect(40, 96, 90, 8); // 病床
        const wt = this.add.text(160, 40, '……这里是……？', { fontFamily: FONT, fontSize: '10px', color: '#6a6a70' }).setOrigin(0.5);
        c.add([w, wt]);
        this.time.delayedCall(dur, () => { c.destroy(); cb(); });
      } else { c.destroy(); cb(); }
    });
  }

  update(_t: number, dt: number) {
    // rain
    if (this.raining) {
      this.rainY = (this.rainY + dt * 0.35) % 20;
      const g = this.rainG; g.clear(); g.lineStyle(1, 0xbcd6ee, 0.5);
      for (let x = -20; x < 340; x += 12) for (let y = -20; y < 200; y += 20) { const yy = y + this.rainY; g.lineBetween(x + (yy % 40) * 0.2, yy, x + (yy % 40) * 0.2 - 3, yy + 6); }
    }
    // forced confetti
    if (this.forcedOn) {
      const g = this.rainG; // reuse layer when not raining
      if (!this.raining) { g.clear(); for (const p of this.confetti) { p.y += (p.s / 60) * dt / 16; if (p.y > 180) p.y = -4; g.fillStyle(p.c, 0.9).fillRect(p.x, p.y, 2, 2); } }
    }
  }

  // ---------------- debug panel (§13) ----------------
  private buildDebug() {
    const d = document.createElement('div');
    d.style.cssText = 'position:fixed;right:8px;top:8px;z-index:9999;display:none;background:#1b1620ee;color:#eee;font:11px/1.5 monospace;padding:8px;border:1px solid #ffd27a;border-radius:6px;max-width:220px;';
    d.innerHTML = `<b style="color:#ffd27a">DEBUG（\` 开关）</b>
      <div>幸福 ${btns('H', [10, 40, 70, 90, 100])}</div>
      <div>觉知 ${btns('A', [0, 40, 70, 100])}</div>
      <div>日 ${btns('D', [1, 2, 3, 4, 5, 6, 7])}</div>
      <div>传送 ${['home', 'plaza', 'bakery', 'grocery', 'clinic', 'lake', 'field', 'well', 'fog'].map((m) => `<button data-tp="${m}">${m}</button>`).join('')}</div>
      <div><button data-clues="1">置齐全部线索</button></div>
      <div>结局 ${['E1', 'E2', 'E3', 'E4'].map((e) => `<button data-end="${e}">${e}</button>`).join('')}</div>`;
    document.body.appendChild(d); this.dbg = d;
    d.addEventListener('click', (e) => {
      const el = e.target as HTMLElement; const world = () => this.scene.get('World') as any;
      if (el.dataset.h) Director.setHappiness(+el.dataset.h);
      else if (el.dataset.a) Director.setAwareness(+el.dataset.a);
      else if (el.dataset.d) { activateDay(+el.dataset.d); this.toast('Day ' + el.dataset.d); }
      else if (el.dataset.tp) world().debugTeleport(el.dataset.tp);
      else if (el.dataset.clues) { ['C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9'].forEach((c) => Director.discoverClue(c)); Director.flags.seen_C9a = Director.flags.seen_C9b = Director.flags.seen_C9c = true; this.toast('线索已置齐（9/9）'); }
      else if (el.dataset.end) world().startEnding(el.dataset.end);
    });
  }
  private toggleDebug() { if (!this.dbg) return; this.dbg.style.display = this.dbg.style.display === 'none' ? 'block' : 'none'; }
}

function btns(kind: string, vals: number[]) { const a = kind === 'H' ? 'h' : kind === 'A' ? 'a' : 'd'; return vals.map((v) => `<button data-${a}="${v}">${v}</button>`).join(''); }
function nameOf(id: string): string { return ({ afu: '阿福', yuan: '圆圆', dabao: '大宝', mimi: '咪咪', fu: '芙医生', gui: '龟爷爷', bird1: '双子鸟', bird2: '双子鸟' } as any)[id] || id; }
function spriteOf(id: string): string { return ({ afu: 'npc_afu', yuan: 'npc_yuan', dabao: 'npc_dabao', mimi: 'npc_mimi', fu: 'npc_fu', gui: 'npc_gui' } as any)[id] || 'npc_afu'; }
