// UIScene.ts: persistent overlay. Dialogue box, sunflower HUD, "按 E" prompt,
// saturation/vignette camera FX driven by director, day/transition overlays.
import Phaser from 'phaser';
import { director } from '../systems/CorruptionDirector';
import { corrupt, tickTurn } from '../systems/TextCorruptor';
import { EROSION_MATRIX } from '../data/gamedata';
import { audio } from '../systems/AudioEngine';

export interface DialogueChoice { label: string; type: 'gentle'|'doubt'|'deny'; }
export interface DialogueLine { speaker?: string; npcKey?: string; text: string; portrait?: number; choices?: DialogueChoice[]; glitch?: boolean; }

class UIScene extends Phaser.Scene {
  box!: Phaser.GameObjects.Container;
  nameText!: Phaser.GameObjects.Text;
  bodyText!: Phaser.GameObjects.Text;
  portrait!: Phaser.GameObjects.Image;
  choiceTexts: Phaser.GameObjects.Text[] = [];
  prompt!: Phaser.GameObjects.Text;
  hud!: Phaser.GameObjects.Container;
  petalImages: Phaser.GameObjects.Rectangle[] = [];
  centerSeed!: Phaser.GameObjects.Arc;
  dayLabel!: Phaser.GameObjects.Text;

  private currentLines: DialogueLine[] = [];
  private idx = 0;
  private active = false;
  private choiceCb: ((c: DialogueChoice)=>void) | null = null;
  private typing = false;
  private fullText = '';
  private typeStart = 0;
  private negativeFx: Phaser.GameObjects.Rectangle | null = null;

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

  create() {
    // Dialogue box (bottom banner)
    this.box = this.add.container(0, 0).setDepth(1000).setVisible(false);
    const bg = this.add.rectangle(160, 156, 312, 44, 0x000000, 0.78).setStrokeStyle(1, 0xffffff);
    this.box.add(bg);
    this.portrait = this.add.image(20, 156, 'portraits', 0).setOrigin(0, 0.5);
    this.box.add(this.portrait);
    this.nameText = this.add.text(44, 140, '', { fontFamily: 'monospace', fontSize: '9px', color: '#ffd86b' });
    this.box.add(this.nameText);
    this.bodyText = this.add.text(44, 150, '', { fontFamily: 'monospace', fontSize: '8px', color: '#ffffff', wordWrap: { width: 256 } });
    this.box.add(this.bodyText);
    for (let i=0;i<3;i++){
      const t = this.add.text(50 + i*88, 168, '', { fontFamily:'monospace', fontSize:'8px', color:'#bfe3ff' });
      this.box.add(t); this.choiceTexts.push(t);
    }

    // "按 E" prompt
    this.prompt = this.add.text(160, 96, '按 E', { fontFamily:'monospace', fontSize:'8px', color:'#ffffff', backgroundColor:'#000000' }).setOrigin(0.5).setDepth(900).setVisible(false);

    // Sunflower HUD (top-left). 12 petals.
    this.hud = this.add.container(4, 8).setDepth(950);
    const cx = 10, cy = 10;
    this.add.rectangle(cx, cy, 22, 22, 0x000000, 0.35).setOrigin(0.5).setDepth(949);
    // draw 12 petals around
    for (let i=0;i<12;i++){
      const ang = (i/12)*Math.PI*2 - Math.PI/2;
      const r = 8;
      const px = cx + Math.cos(ang)*r;
      const py = cy + Math.sin(ang)*r;
      const petal = this.add.rectangle(px, py, 4, 4, 0x553311).setOrigin(0.5);
      this.hud.add(petal);
      this.petalImages.push(petal);
    }
    this.centerSeed = this.add.circle(cx, cy, 3, 0xc8862a).setDepth(951);
    this.centerSeed.setVisible(false);
    this.dayLabel = this.add.text(160, 4, `第 1 天`, { fontFamily:'monospace', fontSize:'8px', color:'#ffe9b0' }).setOrigin(0.5,0).setDepth(950);

    // hook events
    director.on('change', () => this.refreshHud());
    director.on('stage', () => this.applyErosionFx());
    director.on('negativeFlash', () => this.flashNegative());
    director.on('day', () => { this.dayLabel.setText(`第 ${director.day} 天`); });
    this.refreshHud();
    this.applyErosionFx();

    // typewriter timer
    this.time.addEvent({ delay: 30, loop: true, callback: () => this.typeTick() });

    // input: E advances dialogue
    const kb = this.input.keyboard!;
    kb.on('keydown-SPACE', () => this.advance());
    kb.on('keydown-E', () => this.advance());
    kb.on('keydown-ENTER', () => this.advance());
    kb.on('keydown-ONE', () => this.pickChoice(0));
    kb.on('keydown-TWO', () => this.pickChoice(1));
    kb.on('keydown-THREE', () => this.pickChoice(2));
  }

  // Dialogue API
  startDialogue(lines: DialogueLine[], onDone?: () => void, onChoice?: (c: DialogueChoice)=>void) {
    this.currentLines = lines;
    this.idx = 0;
    this.active = true;
    this._onDone = onDone || null;
    this.choiceCb = onChoice || null;
    this.box.setVisible(true);
    this.showLine();
  }
  private _onDone: (()=>void) | null = null;

  private showLine() {
    const line = this.currentLines[this.idx];
    if (!line) { this.endDialogue(); return; }
    tickTurn();
    const stage = director.stage;
    let text = line.text;
    if (line.npcKey) {
      text = corrupt(text, stage, line.npcKey);
    } else if (line.glitch) {
      // leave as is
    }
    if (line.speaker) this.nameText.setText(line.speaker); else this.nameText.setText('');
    if (line.portrait !== undefined) {
      this.portrait.setVisible(true).setFrame(line.portrait);
    } else this.portrait.setVisible(false);
    this.fullText = text;
    this.bodyText.setText('');
    this.typing = true;
    this.typeStart = this.time.now;
    // choices
    this.choiceTexts.forEach(t => t.setText(''));
    if (line.choices && line.choices.length) {
      line.choices.forEach((c, i) => {
        if (this.choiceTexts[i]) this.choiceTexts[i].setText(`${i+1}. ${c.label}`);
      });
    }
    // beep on start
    audio.sfxBlip();
  }

  private typeTick() {
    if (!this.typing) return;
    const elapsed = this.time.now - this.typeStart;
    const n = Math.floor(elapsed / 30);
    if (n >= this.fullText.length) {
      this.bodyText.setText(this.fullText);
      this.typing = false;
    } else {
      this.bodyText.setText(this.fullText.slice(0, n));
    }
  }

  advance() {
    if (!this.active) return;
    const line = this.currentLines[this.idx];
    if (this.typing) {
      // complete immediately
      this.bodyText.setText(this.fullText);
      this.typing = false;
      return;
    }
    if (line && line.choices && line.choices.length) {
      // waiting for choice pick; ignore
      return;
    }
    this.idx++;
    if (this.idx >= this.currentLines.length) { this.endDialogue(); }
    else this.showLine();
  }

  private pickChoice(i: number) {
    if (!this.active) return;
    const line = this.currentLines[this.idx];
    if (!line || !line.choices) return;
    const c = line.choices[i];
    if (!c) return;
    // apply generic effects per §6.1/6.2. Note: 'deny' sadness is applied by the
    // scene's choice callback (拒绝对话 vs 拒绝任务 are distinct §6.3 behaviors),
    // so we only apply the gentle/doubt numeric effects here to avoid double-counting.
    if (c.type === 'gentle') { director.addHappiness(2); }
    else if (c.type === 'doubt') { director.addAwareness(2); }
    if (this.choiceCb) this.choiceCb(c);
    this.idx++;
    if (this.idx >= this.currentLines.length) this.endDialogue();
    else this.showLine();
  }

  private endDialogue() {
    this.active = false;
    this.box.setVisible(false);
    const cb = this._onDone; this._onDone = null;
    if (cb) cb();
  }

  isDialogueActive() { return this.active; }

  showPrompt(text: string) {
    this.prompt.setText(text).setVisible(true);
  }
  hidePrompt() { this.prompt.setVisible(false); }

  // HUD refresh
  refreshHud() {
    const h = director.happiness;
    // petals lit = floor(happiness / 100 * 12)
    const lit = Math.round((h / 100) * 12);
    for (let i=0;i<12;i++){
      const on = i < lit;
      this.petalImages[i].fillColor = on ? 0xffd23b : 0x553311;
    }
    // black seeds appear at S4 / happiness 100
    const row = EROSION_MATRIX.find(r => r.stage === director.stage);
    if (row && row.ui.blackSeeds) this.centerSeed.setVisible(true);
    else this.centerSeed.setVisible(h >= 100);
    // S3 petals over-bright
    if (director.stage === 'S3') this.petalImages.forEach(p => p.fillColor = p.fillColor === 0xffd23b ? 0xffec80 : p.fillColor);
    this.dayLabel.setText(`第 ${director.day} 天`);
  }

  // Camera FX: we expose saturation/vignette values that map scenes read each frame
  // to drive their own camera postFX (so the FX attaches to the active gameplay camera).
  applyErosionFx() {
    const stage = director.stage;
    const row = EROSION_MATRIX.find(r => r.stage === stage)!;
    this._sat = row.saturation;
    this._vignette = (stage === 'S3') ? 0.25 : (stage === 'S4') ? 0.45 : 0;
    audio.setErosion(stage);
  }

  // We expose a saturation value that map scenes read in their update to drive a color matrix.
  private _sat = 1.0;
  private _vignette = 0;
  getSaturation() { return this._sat; }
  getVignette() { return this._vignette; }

  // single-frame negative flash
  flashNegative() {
    if (this.negativeFx) this.negativeFx.destroy();
    const r = this.add.rectangle(160, 90, 320, 180, 0xffffff, 1).setDepth(2000);
    this.negativeFx = r;
    this.time.delayedCall(60, () => { r.destroy(); this.negativeFx = null; });
  }
}

export { UIScene };
