import Phaser from 'phaser';
import { audio } from '../AudioDirector';
import { director } from '../CorruptionDirector';
import { MAP_KEYS, MAP_LABELS, type EndingId } from '../data';

export type DialogueChoice = 'gentle' | 'hesitate' | 'negative';

interface DialogueOptions {
  speaker: string;
  text: string | string[];
  portrait?: number;
  choices?: Array<{ id: DialogueChoice; label: string }>;
  clean?: boolean;
}

interface ActiveDialogue {
  pages: string[];
  page: number;
  choices?: Array<{ id: DialogueChoice; label: string }>;
  selection: number;
  resolve: (choice?: DialogueChoice) => void;
}

export class UIScene extends Phaser.Scene {
  private hud!: Phaser.GameObjects.Graphics;
  private dayText!: Phaser.GameObjects.Text;
  private questText!: Phaser.GameObjects.Text;
  private promptText!: Phaser.GameObjects.Text;
  private toastText!: Phaser.GameObjects.Text;
  private dialoguePanel!: Phaser.GameObjects.Graphics;
  private portrait!: Phaser.GameObjects.Image;
  private speakerText!: Phaser.GameObjects.Text;
  private bodyText!: Phaser.GameObjects.Text;
  private choiceTexts: Phaser.GameObjects.Text[] = [];
  private active?: ActiveDialogue;
  private debugDom?: Phaser.GameObjects.DOMElement;

  constructor() { super({ key: 'UIScene', active: false }); }

  create(): void {
    this.cameras.main.setRoundPixels(true);
    this.hud = this.add.graphics().setDepth(100);
    this.dayText = this.add.text(4, 28, '', this.pixelStyle(8, '#fff7d7')).setDepth(101).setShadow(1, 1, '#4b3128', 0, true, true);
    this.questText = this.add.text(316, 4, '', this.pixelStyle(7, '#fff7d7')).setOrigin(1, 0).setAlign('right').setDepth(101).setShadow(1, 1, '#4b3128', 0, true, true);
    this.promptText = this.add.text(160, 144, '', this.pixelStyle(8, '#fff6c7')).setOrigin(0.5).setPadding(4, 2, 4, 2).setBackgroundColor('#402a25').setDepth(110).setVisible(false);
    this.toastText = this.add.text(160, 42, '', this.pixelStyle(8, '#3d2925')).setOrigin(0.5).setPadding(6, 3, 6, 3).setBackgroundColor('#fff0ae').setDepth(120).setVisible(false);
    this.dialoguePanel = this.add.graphics().setDepth(130).setVisible(false);
    this.portrait = this.add.image(29, 153, 'portraits', 0).setDisplaySize(40, 40).setDepth(131).setVisible(false);
    this.speakerText = this.add.text(54, 132, '', this.pixelStyle(8, '#f0ad3f')).setDepth(131).setVisible(false);
    this.bodyText = this.add.text(54, 144, '', this.pixelStyle(8, '#4b3128')).setWordWrapWidth(254).setLineSpacing(2).setDepth(131).setVisible(false);
    this.createDebugPanel();
    this.bindKeys();
    this.redraw();
    director.on('change', this.redraw, this);
    director.on('task-complete', this.taskComplete, this);
    director.on('task-refused', () => this.toast('任务已拒绝。'), this);
    director.on('clue', (_id: string, content: string) => this.toast(`发现线索：${content}`, 2600), this);
    director.on('sunset', () => { audio.beep('bell'); this.toast('黄昏钟声响起了。回小屋睡觉。', 3000); }, this);
    director.on('forced-cheer', () => this.toast('欢乐庆典开始了。边缘仍有一条路。', 3000), this);
    this.events.once(Phaser.Scenes.Events.SHUTDOWN, () => {
      director.off('change', this.redraw, this);
      director.off('task-complete', this.taskComplete, this);
      director.off('task-refused'); director.off('clue'); director.off('sunset'); director.off('forced-cheer');
    });
  }

  private pixelStyle(size: number, color: string): Phaser.Types.GameObjects.Text.TextStyle {
    return { fontFamily: '"Courier New", "PingFang SC", "Microsoft YaHei", monospace', fontSize: `${size}px`, fontStyle: 'bold', color };
  }

  private bindKeys(): void {
    const keyboard = this.input.keyboard;
    if (!keyboard) return;
    keyboard.on('keydown-E', () => this.advance());
    keyboard.on('keydown-ENTER', () => this.advance());
    keyboard.on('keydown-UP', () => this.moveChoice(-1));
    keyboard.on('keydown-DOWN', () => this.moveChoice(1));
    keyboard.on('keydown-ONE', () => this.choose(0));
    keyboard.on('keydown-TWO', () => this.choose(1));
    keyboard.on('keydown-THREE', () => this.choose(2));
    keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.BACKTICK).on('down', () => this.toggleDebug());
  }

  private redraw = (): void => {
    this.drawSunflower();
    this.dayText.setText(`Day ${director.snapshot.day}`);
    const pending = director.tasksForDay().find((task) => !director.snapshot.completed.has(task.id) && !director.snapshot.refused.has(task.id));
    let quest = director.snapshot.boardRead ? (pending ? `${pending.id}  ${pending.title}` : (director.snapshot.sunset ? '回小屋睡觉' : '自由活动')) : '前往公告板';
    if (director.snapshot.day === 7 && director.snapshot.festivalStarted && director.ending() === 'E3') quest = '走向雾墙';
    this.questText.setText(quest).setWordWrapWidth(170);
  };

  private drawSunflower(): void {
    const value = director.snapshot.happiness;
    const lit = value <= 20 ? Math.round(value / 10)
      : value <= 50 ? 3 + Math.floor((value - 21) * 4 / 30)
        : value <= 80 ? 7 + Math.floor((value - 51) * 3 / 30)
          : value < 100 ? 10 + Math.floor((value - 81) * 3 / 19) : 12;
    this.hud.clear();
    this.hud.fillStyle(0x3d2925, 0.65).fillRoundedRect(3, 3, 29, 24, 3);
    for (let i = 0; i < 12; i += 1) {
      const angle = (Math.PI * 2 * i) / 12 - Math.PI / 2;
      const x = 17.5 + Math.cos(angle) * 8;
      const y = 14.5 + Math.sin(angle) * 8;
      this.hud.fillStyle(0x4b3128, 1).fillCircle(x, y, 3.2);
      this.hud.fillStyle(i < lit ? (value >= 81 ? 0xffff6b : 0xffd53e) : 0x8e7653, 1).fillCircle(x, y, 2.3);
    }
    this.hud.fillStyle(value === 100 ? 0x2a211d : 0x9a592d, 1).fillCircle(17.5, 14.5, 5);
    if (value === 100) {
      this.hud.fillStyle(0x070707, 1);
      [[16, 13], [19, 14], [16, 17], [20, 17]].forEach(([x, y]) => this.hud.fillRect(x, y, 1, 1));
    }
  }

  setPrompt(label?: string): void {
    this.promptText.setVisible(Boolean(label)).setText(label ? `按 E  ${label}` : '');
  }

  toast(message: string, duration = 1800): void {
    this.toastText.setText(message).setVisible(true).setAlpha(1);
    this.tweens.killTweensOf(this.toastText);
    this.tweens.add({ targets: this.toastText, alpha: 0, delay: duration, duration: 300, onComplete: () => this.toastText.setVisible(false) });
  }

  showDialogue(options: DialogueOptions): Promise<DialogueChoice | undefined> {
    if (this.active) return Promise.resolve(undefined);
    director.setDialogueOpen(true);
    const pages = (Array.isArray(options.text) ? options.text : [options.text]).map((text) => options.clean ? text : director.corruptText(text, options.speaker));
    this.dialoguePanel.setVisible(true).clear().fillStyle(0x3e2924, 0.98).fillRect(2, 126, 316, 52).fillStyle(0xffefbd, 1).fillRect(5, 129, 310, 46);
    this.portrait.setFrame(options.portrait ?? 0).setVisible(true);
    this.speakerText.setText(options.speaker).setVisible(true);
    this.bodyText.setText(pages[0]).setVisible(true);
    audio.beep('dialogue');
    return new Promise((resolve) => {
      this.active = { pages, page: 0, choices: options.choices, selection: 0, resolve };
    });
  }

  private advance(): void {
    if (!this.active) return;
    if (this.active.page < this.active.pages.length - 1) {
      this.active.page += 1;
      this.bodyText.setText(this.active.pages[this.active.page]);
      audio.beep('dialogue');
      return;
    }
    if (this.active.choices?.length) {
      if (this.choiceTexts.length === 0) this.renderChoices();
      else this.choose(this.active.selection);
      return;
    }
    this.closeDialogue();
  }

  private renderChoices(): void {
    this.bodyText.setVisible(false);
    this.active?.choices?.forEach((choice, index) => {
      const text = this.add.text(58, 139 + index * 11, `${index + 1}. ${choice.label}`, this.pixelStyle(7, '#4b3128')).setDepth(132);
      this.choiceTexts.push(text);
    });
    this.updateChoiceStyles();
  }

  private moveChoice(delta: number): void {
    if (!this.active?.choices || this.choiceTexts.length === 0) return;
    this.active.selection = Phaser.Math.Wrap(this.active.selection + delta, 0, this.active.choices.length);
    this.updateChoiceStyles();
  }

  private updateChoiceStyles(): void {
    this.choiceTexts.forEach((text, index) => text.setColor(index === this.active?.selection ? '#c75f38' : '#4b3128'));
  }

  private choose(index: number): void {
    const choice = this.active?.choices?.[index];
    if (!choice) return;
    this.closeDialogue(choice.id);
  }

  private closeDialogue(choice?: DialogueChoice): void {
    const resolve = this.active?.resolve;
    this.active = undefined;
    this.dialoguePanel.setVisible(false);
    this.portrait.setVisible(false);
    this.speakerText.setVisible(false);
    this.bodyText.setVisible(false);
    this.choiceTexts.forEach((text) => text.destroy());
    this.choiceTexts = [];
    director.setDialogueOpen(false);
    resolve?.(choice);
  }

  private taskComplete = (task: { id: string; title: string }): void => {
    audio.beep('task');
    this.toast(`${task.id} 完成：${task.title}`, 2400);
  };

  private createDebugPanel(): void {
    const sceneOptions = MAP_KEYS.map((key) => `<option value="${key}">${MAP_LABELS[key]}</option>`).join('');
    const html = `<section class="debug-panel" aria-label="Debug Panel">
      <h2>Debug Panel</h2>
      <div class="debug-row"><label>Happiness</label><input data-field="happiness" type="number" min="0" max="100" value="30"><button data-action="happiness">Set</button></div>
      <div class="debug-row"><label>Awareness</label><input data-field="awareness" type="number" min="0" max="100" value="0"><button data-action="awareness">Set</button></div>
      <div class="debug-row"><label>Day</label><input data-field="day" type="number" min="1" max="7" value="1"><button data-action="day">Set</button></div>
      <div class="debug-row"><label>Teleport</label><select data-field="scene">${sceneOptions}</select><button data-action="teleport">Go</button></div>
      <div class="debug-row"><button data-action="clues">Set all clues</button></div>
      <div class="ending-grid">${(['E1', 'E2', 'E3', 'E4'] as EndingId[]).map((id) => `<button data-ending="${id}">${id}</button>`).join('')}</div>
    </section>`;
    this.debugDom = this.add.dom(190, 90).createFromHTML(html).setScale(0.7).setDepth(500).setVisible(false);
    const node = this.debugDom.node as HTMLElement;
    node.addEventListener('click', (event) => {
      const target = event.target as HTMLElement;
      const action = target.dataset.action;
      const ending = target.dataset.ending as EndingId | undefined;
      const input = (name: string) => node.querySelector<HTMLInputElement | HTMLSelectElement>(`[data-field="${name}"]`);
      if (action === 'happiness') director.setHappiness(Number(input('happiness')?.value));
      if (action === 'awareness') director.setAwareness(Number(input('awareness')?.value));
      if (action === 'day') director.setDay(Number(input('day')?.value));
      if (action === 'teleport') director.emit('debug-teleport', input('scene')?.value);
      if (action === 'clues') director.discoverAllClues();
      if (ending) director.emit('force-ending', ending);
    });
  }

  private toggleDebug(): void {
    if (!this.debugDom) return;
    this.debugDom.setVisible(!this.debugDom.visible);
  }
}
