import Phaser from 'phaser';
import { DEBUG_TELEPORT_SCENES, GAME_HEIGHT, GAME_WIDTH, SCENE_KEYS } from '../data/constants';
import type { DialogLine } from '../data/dialogues';
import { Director } from '../systems/CorruptionDirector';
import { gameEvents } from '../systems/EventBus';
import { audio } from '../audio/ProceduralAudio';
import type { EndingId } from '../data/endings';
import { parseDebugKey } from '../systems/debugKeys';

type DialogCb = (choice?: 'gentle' | 'hesitant' | 'negate') => void;

export class UIScene extends Phaser.Scene {
  private petals: Phaser.GameObjects.Image[] = [];
  private center!: Phaser.GameObjects.Image;
  private promptText!: Phaser.GameObjects.Text;
  private toastText!: Phaser.GameObjects.Text;
  private dialogRoot!: Phaser.GameObjects.Container;
  private dialogName!: Phaser.GameObjects.Text;
  private dialogBody!: Phaser.GameObjects.Text;
  private dialogPortrait!: Phaser.GameObjects.Image;
  private optionTexts: Phaser.GameObjects.Text[] = [];
  private queue: DialogLine[] = [];
  private onDialogDone: DialogCb | null = null;
  private showingOptions = false;
  private debugRoot!: Phaser.GameObjects.Container;
  private debugVisible = false;
  private dayLabel!: Phaser.GameObjects.Text;
  private teleportScenes: string[] = [];
  private teleportCycle = 0;

  constructor() {
    super(SCENE_KEYS.UI);
  }

  create(): void {
    // Sunflower HUD top-left — no numbers
    const hx = 20;
    const hy = 20;
    for (let i = 0; i < 12; i++) {
      const a = (i / 12) * Math.PI * 2 - Math.PI / 2;
      const img = this.add
        .image(hx + Math.cos(a) * 10, hy + Math.sin(a) * 10, 'sunflower', i)
        .setScrollFactor(0)
        .setDepth(100)
        .setScale(0.7)
        .setAlpha(0.25);
      this.petals.push(img);
    }
    this.center = this.add
      .image(hx, hy, 'sunflower', 12)
      .setScrollFactor(0)
      .setDepth(101)
      .setScale(0.8);

    this.dayLabel = this.add
      .text(GAME_WIDTH - 8, 6, '', {
        fontFamily: 'monospace',
        fontSize: '8px',
        color: '#fff8e0',
        backgroundColor: '#00000055',
        padding: { x: 3, y: 2 },
      })
      .setOrigin(1, 0)
      .setScrollFactor(0)
      .setDepth(100);

    this.promptText = this.add
      .text(GAME_WIDTH / 2, GAME_HEIGHT - 56, '', {
        fontFamily: 'monospace',
        fontSize: '9px',
        color: '#ffffff',
        backgroundColor: '#00000088',
        padding: { x: 4, y: 2 },
      })
      .setOrigin(0.5)
      .setScrollFactor(0)
      .setDepth(100)
      .setVisible(false);

    this.toastText = this.add
      .text(GAME_WIDTH / 2, 36, '', {
        fontFamily: 'monospace',
        fontSize: '9px',
        color: '#503020',
        backgroundColor: '#fff8e0cc',
        padding: { x: 6, y: 3 },
      })
      .setOrigin(0.5)
      .setScrollFactor(0)
      .setDepth(110)
      .setAlpha(0);

    // Dialog
    const panel = this.add.image(GAME_WIDTH / 2, GAME_HEIGHT - 28, 'dialog_panel').setDisplaySize(GAME_WIDTH - 8, 52);
    this.dialogPortrait = this.add.image(28, GAME_HEIGHT - 28, 'portraits', 0).setScale(1);
    this.dialogName = this.add.text(50, GAME_HEIGHT - 50, '', {
      fontFamily: 'monospace',
      fontSize: '9px',
      color: '#804020',
    });
    this.dialogBody = this.add.text(50, GAME_HEIGHT - 38, '', {
      fontFamily: 'monospace',
      fontSize: '9px',
      color: '#302010',
      wordWrap: { width: 250 },
    });
    this.dialogRoot = this.add
      .container(0, 0, [panel, this.dialogPortrait, this.dialogName, this.dialogBody])
      .setScrollFactor(0)
      .setDepth(120)
      .setVisible(false);

    for (let i = 0; i < 3; i++) {
      const t = this.add
        .text(50, GAME_HEIGHT - 28 + i * 10, '', {
          fontFamily: 'monospace',
          fontSize: '8px',
          color: '#2060a0',
        })
        .setScrollFactor(0)
        .setDepth(121)
        .setVisible(false)
        .setInteractive({ useHandCursor: true });
      const idx = i;
      t.on('pointerdown', () => this.pickOption(idx));
      this.optionTexts.push(t);
    }

    this.buildDebug();
    this.refreshHud();

    gameEvents.on('petals', this.onPetals as (...a: unknown[]) => void);
    gameEvents.on('happiness', () => this.refreshHud());
    gameEvents.on('day', () => this.refreshHud());
    gameEvents.on('prompt', this.onPrompt as (...a: unknown[]) => void);
    gameEvents.on('toast', this.onToast as (...a: unknown[]) => void);
    gameEvents.on('dialog', this.onDialog as (...a: unknown[]) => void);
    gameEvents.on('taskComplete', () => {
      audio.ding();
      this.onToast('任务完成');
    });

    this.input.keyboard?.on('keydown-E', () => this.advanceDialog());
    this.input.keyboard?.on('keydown-SPACE', () => this.advanceDialog());
    this.input.keyboard?.on('keydown-ONE', () => this.pickOption(0));
    this.input.keyboard?.on('keydown-TWO', () => this.pickOption(1));
    this.input.keyboard?.on('keydown-THREE', () => this.pickOption(2));
    this.input.keyboard?.on('keydown', (ev: KeyboardEvent) => {
      if (ev.key === '`' || ev.code === 'Backquote') {
        ev.preventDefault();
        this.toggleDebug();
      }
    });

    this.events.on('shutdown', () => {
      gameEvents.off('petals', this.onPetals as (...a: unknown[]) => void);
    });
  }

  private onPetals = (count: unknown, seeds: unknown) => {
    const n = count as number;
    const black = seeds as boolean;
    for (let i = 0; i < 12; i++) {
      this.petals[i]!.setAlpha(i < n ? 1 : 0.2);
      // S3 overbright
      if (Director.stage === 'S3' || Director.stage === 'S4') {
        this.petals[i]!.setTint(i < n ? 0xffffaa : 0xffffff);
      } else {
        this.petals[i]!.clearTint();
      }
    }
    this.center.setFrame(black ? 13 : 12);
  };

  private refreshHud(): void {
    const p = Director.getPetals();
    const seeds = Director.getBlackSeeds();
    this.onPetals(p, seeds);
    this.dayLabel.setText(`Day ${Director.day}`);
  }

  private onPrompt = (show: unknown, text: unknown) => {
    if (this.dialogRoot.visible) {
      this.promptText.setVisible(false);
      return;
    }
    this.promptText.setVisible(!!show);
    this.promptText.setText(String(text || ''));
  };

  private onToast = (msg: unknown) => {
    this.toastText.setText(String(msg));
    this.tweens.killTweensOf(this.toastText);
    this.toastText.setAlpha(1);
    this.tweens.add({
      targets: this.toastText,
      alpha: 0,
      delay: 1400,
      duration: 400,
    });
  };

  private onDialog = (lines: unknown, cb: unknown) => {
    this.queue = lines as DialogLine[];
    this.onDialogDone = cb as DialogCb;
    this.showNextLine();
  };

  private showNextLine(): void {
    if (this.queue.length === 0) {
      this.dialogRoot.setVisible(false);
      for (const o of this.optionTexts) o.setVisible(false);
      this.showingOptions = false;
      const done = this.onDialogDone;
      this.onDialogDone = null;
      done?.();
      return;
    }
    const line = this.queue[0]!;
    this.dialogRoot.setVisible(true);
    this.dialogName.setText(line.speaker);
    this.dialogBody.setText(line.text);
    this.dialogPortrait.setFrame(0); // always smile per pillar 2
    audio.beep();
    this.showingOptions = false;
    for (const o of this.optionTexts) o.setVisible(false);

    if (line.options && line.options.length > 0 && this.queue.length === 1) {
      this.showingOptions = true;
      line.options.forEach((opt, i) => {
        const t = this.optionTexts[i];
        if (!t) return;
        t.setText(`${i + 1}. ${opt.label}`);
        t.setVisible(true);
      });
    }
  }

  private advanceDialog(): void {
    if (!this.dialogRoot.visible) return;
    if (this.showingOptions) return; // must pick
    this.queue.shift();
    this.showNextLine();
  }

  private pickOption(idx: number): void {
    if (!this.showingOptions || !this.dialogRoot.visible) return;
    const line = this.queue[0];
    const opt = line?.options?.[idx];
    if (!opt) return;
    this.queue = [];
    this.dialogRoot.setVisible(false);
    for (const o of this.optionTexts) o.setVisible(false);
    this.showingOptions = false;
    const done = this.onDialogDone;
    this.onDialogDone = null;
    done?.(opt.choice);
  }

  private buildDebug(): void {
    const bg = this.add.rectangle(GAME_WIDTH / 2, GAME_HEIGHT / 2, 280, 150, 0x101018, 0.92).setStrokeStyle(1, 0x80ffc0);
    const title = this.add.text(50, 20, 'DEBUG ` 关闭', {
      fontFamily: 'monospace',
      fontSize: '10px',
      color: '#80ffc0',
    });
    const lines = [
      'H/J 幸福±10  K/L 觉知±10  Shift+1-7 设日  C线索',
      '传送0-9: 0屋1广2包3杂4诊5湖6田7井8雾9白',
      'V 循环十场景  F1-F4 结局  N负片 P庆典',
    ];
    const body = this.add.text(40, 36, lines.join('\n'), {
      fontFamily: 'monospace',
      fontSize: '8px',
      color: '#c0ffe0',
      lineSpacing: 3,
    });
    this.debugRoot = this.add
      .container(0, 0, [bg, title, body])
      .setScrollFactor(0)
      .setDepth(200)
      .setVisible(false);

    /** All 10 map scenes for §13 teleport-to-any (shared constant) */
    this.teleportScenes = [...DEBUG_TELEPORT_SCENES];

    this.input.keyboard?.on('keydown', (ev: KeyboardEvent) => {
      if (!this.debugVisible) return;
      this.applyDebugAction(
        parseDebugKey({ key: ev.key, code: ev.code, shiftKey: ev.shiftKey }),
        title,
      );
    });
  }

  /** Apply shipped parseDebugKey result to Director / events (testable path). */
  applyDebugAction(
    action: ReturnType<typeof parseDebugKey>,
    title?: Phaser.GameObjects.Text,
  ): void {
    switch (action.type) {
      case 'happiness':
        Director.setHappiness(Director.happiness + action.delta, { force: true });
        break;
      case 'awareness':
        if (action.delta > 0) Director.addAwareness(action.delta);
        else {
          Director.awareness = Math.max(0, Director.awareness + action.delta);
          gameEvents.emit('awareness', Director.awareness);
        }
        break;
      case 'setDay':
        Director.setDay(action.day);
        break;
      case 'grantClues':
        Director.grantAllClues();
        break;
      case 'teleport':
        gameEvents.emit('teleport', { scene: action.scene });
        break;
      case 'teleportCycle':
        this.teleportCycle = (this.teleportCycle + 1) % this.teleportScenes.length;
        gameEvents.emit('teleport', { scene: this.teleportScenes[this.teleportCycle] });
        break;
      case 'negativeFlash':
        gameEvents.emit('negativeFlash');
        break;
      case 'forcedCelebration':
        Director.triggerForcedCelebration();
        break;
      case 'forceEnding':
        this.forceEnd(action.id);
        break;
      default:
        break;
    }
    this.refreshHud();
    if (title) this.refreshDebugStats(title);
  }

  private refreshDebugStats(title: Phaser.GameObjects.Text): void {
    title.setText(
      `DEBUG H${Director.happiness} A${Director.awareness} D${Director.day} ${Director.stage} 线索${Director.clues.size}`,
    );
  }

  private forceEnd(id: EndingId): void {
    Director.forceEnding(id);
    // stop map scenes
    for (const k of Object.values(SCENE_KEYS)) {
      if (k !== SCENE_KEYS.ENDING && k !== SCENE_KEYS.BOOT && this.scene.isActive(k)) {
        this.scene.stop(k);
      }
    }
    this.scene.start(SCENE_KEYS.ENDING, { endingId: id });
  }

  private toggleDebug(): void {
    this.debugVisible = !this.debugVisible;
    this.debugRoot.setVisible(this.debugVisible);
  }
}
