// CorruptionDirector：全部状态与视听参数的唯一真源（PRD §6.4）
// 普通 TS 单例 + 事件发射器。任何视听崩坏不得绕过本矩阵私自触发。
import Phaser from "phaser";

export type Stage = 0 | 1 | 2 | 3 | 4;
export type Expr = "smile" | "flat" | "off" | "blink";

// NPC 个体阈值偏移（PRD §4）：+ 表示更晚崩坏，− 表示更早
export const NPC_OFFSET: Record<string, number | null> = {
  afu: 0, yuanyuan: 15, dabao: 0, mimi: -10, fu: null, gui: null, bird: 0,
};

export interface QuestDef {
  id: string; day: number; title: string; reward: number; refusable?: boolean;
}

// 任务清单（PRD §7，封闭 15 个）
export const QUESTS: QuestDef[] = [
  { id: "T1", day: 1, title: "从圆圆处取蜂蜜面包送给大宝、咪咪、龟爷爷", reward: 15 },
  { id: "T2", day: 1, title: "给广场花坛浇水 ×3", reward: 10 },
  { id: "T3", day: 1, title: "与任意三位村民问好", reward: 10 },
  { id: "T4", day: 2, title: "替大宝送信 ×3（收件人：圆圆、咪咪、芙医生）", reward: 15 },
  { id: "T5", day: 2, title: "帮咪咪清点货架", reward: 10 },
  { id: "T6", day: 3, title: "去花田采莓果 ×5", reward: 10 },
  { id: "T7", day: 3, title: "湖畔野餐", reward: 15 },
  { id: "T8", day: 4, title: "从圆圆处取蜂蜜面包送给大宝、咪咪、龟爷爷", reward: 15 },
  { id: "T9", day: 4, title: "给广场花坛浇水 ×3", reward: 10 },
  { id: "T10", day: 4, title: "与任意三位村民问好", reward: 10 },
  { id: "T11", day: 5, title: "帮圆圆揉面", reward: 10, refusable: true },
  { id: "T12", day: 5, title: "擦拭公告板", reward: 10, refusable: true },
  { id: "T13", day: 6, title: "在广场挂彩带 ×4", reward: 10 },
  { id: "T14", day: 6, title: "保持微笑 60 秒", reward: 15 },
  { id: "T15", day: 7, title: "参加第 413 届丰收庆典", reward: 0 },
];

export type QuestStatus = "open" | "done" | "refused";

const DAY_LIMIT_MS = 330_000; // 单日游戏内计时上限 → 黄昏（保底）

export class CorruptionDirector extends Phaser.Events.EventEmitter {
  private static inst: CorruptionDirector;
  static get(): CorruptionDirector {
    if (!this.inst) this.inst = new CorruptionDirector();
    return this.inst;
  }

  // ---- 会话状态（无存档，仅内存） ----
  playerName = "小满";
  day = 1;
  happiness = 30;
  awareness = 0;
  clues = new Set<string>();
  questStatus: Record<string, QuestStatus> = {};
  playStart = 0; // 真实游玩计时起点
  overflowPool = 0; // 满格态隐藏溢出池
  escapes = 0; // 逃离欢乐庆典计数（E4）
  refusals = 0;
  e4ok = false; // Day5 起幸福持续 ≤10 的跟踪
  dusk = false;
  announced = false;
  celebrationStarted = false; // D7 到场
  endingPlayed = false;
  // 日内进度
  breadHeld = 0; breadDelivered = new Set<string>();
  lettersHeld = 0; lettersDelivered = new Set<string>();
  shelves = new Set<string>();
  berries = new Set<string>();
  watered = new Set<string>();
  ribbons = new Set<string>();
  wipes = 0;
  greeted = new Set<string>();
  talkCounts: Record<string, number> = {};
  nagged = new Set<string>();
  smallActs: Record<string, number> = {};
  stared = new Set<string>();
  guiChain = new Set<number>();
  t14done = false;
  dayStartAt = 0;
  private lowSince: number | null = null;
  celebrationActive = false;
  pendingSpawn = "entry";
  currentScene = "house";
  cutscene = false;
  t11Accepted = false;
  t12Accepted = false;
  e3Mode = false;

  reset(name: string) {
    this.playerName = name || "小满";
    this.day = 1; this.happiness = 30; this.awareness = 0;
    this.clues.clear(); this.questStatus = {};
    this.playStart = performance.now();
    this.overflowPool = 0; this.escapes = 0; this.refusals = 0;
    this.e4ok = false; this.endingPlayed = false; this.celebrationStarted = false;
    this.guiChain.clear(); this.t14done = false; this.celebrationActive = false;
    this.lowSince = null; this.cutscene = false; this.e3Mode = false;
    this.e4okInit = false;
    this.startDay(1);
  }

  startDay(day: number) {
    this.day = Phaser.Math.Clamp(day, 1, 7);
    this.dusk = false; this.announced = false;
    this.breadHeld = 0; this.breadDelivered.clear();
    this.lettersHeld = 0; this.lettersDelivered.clear();
    this.shelves.clear(); this.berries.clear(); this.watered.clear();
    this.ribbons.clear(); this.wipes = 0;
    this.greeted.clear(); this.talkCounts = {}; this.nagged.clear();
    this.smallActs = {}; this.stared.clear();
    this.t11Accepted = false; this.t12Accepted = false;
    this.dayStartAt = performance.now();
    for (const q of QUESTS) if (q.day === this.day) this.questStatus[q.id] = "open";
    if (this.day >= 5 && !this.e4okInit) { this.e4ok = this.happiness <= 10; this.e4okInit = true; }
    this.emit("day", this.day);
    this.emit("happiness", this.happiness);
  }
  private e4okInit = false;

  get playMinutes(): number {
    return (performance.now() - this.playStart) / 60000;
  }
  get playTimeText(): string {
    const s = Math.floor((performance.now() - this.playStart) / 1000);
    return `${Math.floor(s / 60)} 分 ${s % 60} 秒`;
  }

  // ---- 侵蚀阶段（§6.4 唯一真源） ----
  static stageOf(h: number): Stage {
    if (h >= 100) return 4;
    if (h >= 81) return 3;
    if (h >= 51) return 2;
    if (h >= 21) return 1;
    return 0;
  }
  get stage(): Stage { return CorruptionDirector.stageOf(this.happiness); }

  // NPC 个体表情档（含阈值偏移；fu/gui 不参与侵蚀）
  npcExpr(npc: string): Expr {
    const base = npc.startsWith("bird") ? "bird" : npc;
    const off = NPC_OFFSET[base];
    if (off === null || off === undefined) return "smile";
    const st = CorruptionDirector.stageOf(Phaser.Math.Clamp(this.happiness - off, 0, 100));
    return st >= 3 ? "flat" : "smile";
  }
  npcStage(npc: string): Stage {
    const base = npc.startsWith("bird") ? "bird" : npc;
    const off = NPC_OFFSET[base];
    if (off === null || off === undefined) return 0;
    return CorruptionDirector.stageOf(Phaser.Math.Clamp(this.happiness - off, 0, 100));
  }

  // 视觉参数矩阵
  get visual() {
    const s = this.stage;
    return {
      saturation: [0.9, 1.0, 1.15, 1.3, 1.4][s],
      vignette: s >= 4 ? 0.5 : s >= 3 ? 0.32 : 0,
      negFlashPerMin: s >= 4 ? 0.4 : 0,
      offFlashPerMin: s >= 4 ? 0.6 : 0,
      blinkInterval: s >= 2 ? 5000 : 2000,
    };
  }
  // 音频参数矩阵
  get audioParams() {
    const s = this.stage;
    return {
      rate: [1, 1, 0.97, 0.92, 0.84][s],
      lowpass: s >= 4 ? 4000 : s >= 3 ? 8000 : 18000,
      birds: s >= 4 ? 0 : 1,
    };
  }

  // ---- 幸福值（§6.1） ----
  addHappiness(v: number, silent = false) {
    if (v < 0 && this.happiness >= 100) {
      // 强制维持：小额扣分累积进隐藏溢出池
      this.overflowPool += -v;
      if (this.overflowPool >= 15) {
        this.overflowPool = 0;
        this.emit("negflash");
      }
      return;
    }
    this.happiness = Phaser.Math.Clamp(this.happiness + v, 0, 100);
    if (this.day >= 5 && this.happiness > 10) this.e4ok = false;
    if (!silent) this.emit("happiness", this.happiness);
    this.emit("stage", this.stage);
  }
  setHappiness(v: number) {
    this.happiness = Phaser.Math.Clamp(v, 0, 100);
    if (this.day >= 5 && this.happiness > 10) this.e4ok = false;
    this.emit("happiness", this.happiness);
    this.emit("stage", this.stage);
  }

  // ---- 觉知值（§6.2，暗线，只升不降，永不显示） ----
  addAwareness(v: number) {
    this.awareness = Phaser.Math.Clamp(this.awareness + v, 0, 100);
  }
  setAwareness(v: number) { this.awareness = Phaser.Math.Clamp(v, 0, 100); }

  // 小互动 +1（浇花/喂食/摸头，每类每日上限 3 次）
  smallAct(kind: string): boolean {
    const n = this.smallActs[kind] ?? 0;
    if (n >= 3) return false;
    this.smallActs[kind] = n + 1;
    this.addHappiness(1);
    return true;
  }

  // 注视古井/雾墙 5 秒（各每日 1 次，+3）
  stare(kind: "well" | "fog") {
    if (this.stared.has(kind)) return;
    this.stared.add(kind);
    this.addAwareness(3);
  }

  // ---- 悲伤行为（§6.3 封闭清单 5 项）----
  sadAct(kind: "refuse" | "negative" | "idle" | "nag" | "rain") {
    this.addHappiness(-5);
    this.addAwareness(3);
    this.emit("sadact", kind); // 最近的 NPC 转头看向玩家一次
  }

  // ---- 线索（§8，每处 +8） ----
  foundClue(id: string): boolean {
    if (this.clues.has(id)) return false;
    this.clues.add(id);
    this.addAwareness(8);
    this.emit("clue", id);
    return true;
  }

  // ---- 任务 ----
  questsOfDay(): QuestDef[] { return QUESTS.filter(q => q.day === this.day); }
  isOpen(id: string) { return this.questStatus[id] === "open"; }
  completeQuest(id: string) {
    if (this.questStatus[id] !== "open") return;
    this.questStatus[id] = "done";
    const q = QUESTS.find(x => x.id === id)!;
    if (q.reward > 0) this.addHappiness(q.reward);
    this.emit("quest", id);
    this.checkDusk();
  }
  refuseQuest(id: string) {
    if (this.questStatus[id] !== "open") return;
    this.questStatus[id] = "refused";
    this.refusals++;
    this.sadAct("refuse"); // 拒绝任务 = 悲伤行为，且拒绝被记录
    this.emit("quest", id);
    this.checkDusk();
  }
  checkDusk() {
    if (this.dusk || this.day >= 7) return;
    const open = this.questsOfDay().some(q => this.questStatus[q.id] === "open");
    if (!open) this.triggerDusk();
  }
  triggerDusk() {
    if (this.dusk) return;
    this.dusk = true;
    this.emit("dusk");
  }

  // 每帧钟摆：由 UIScene 驱动
  tick(_time: number, _dt: number) {
    if (this.endingPlayed || this.cutscene) return;
    // 保底黄昏计时
    if (!this.dusk && this.day < 7 && performance.now() - this.dayStartAt > DAY_LIMIT_MS) this.triggerDusk();
    // 幸福 <30 持续 2 分钟 → 强制欢乐庆典（§6.1 反制）
    if (this.happiness < 30 && !this.celebrationActive) {
      if (this.lowSince === null) this.lowSince = performance.now();
      else if (performance.now() - this.lowSince > 120_000) {
        this.lowSince = null;
        this.celebrationActive = true;
        this.emit("forcedCelebration");
      }
    } else if (this.happiness >= 30) {
      this.lowSince = null;
    }
  }
  celebrationEnd(escaped: boolean) {
    this.celebrationActive = false;
    this.lowSince = null;
    if (escaped) this.escapes++;
    else this.setHappiness(50);
  }

  // ---- 结局判定（§9 优先级自上而下） ----
  decideEnding(atFog: boolean): "E4" | "E3" | "E2" | "E1" {
    if (this.e4ok && this.escapes >= 3) return "E4";
    if (atFog && this.awareness >= 70 && this.clues.size >= 6) return "E3";
    if (this.awareness >= 30 && this.awareness <= 69) return "E2";
    if (this.awareness <= 29 && this.happiness >= 90) return "E1";
    // ponytail: 封闭表未覆盖的组合（如觉知≥70但不去雾墙）——回收是系统的默认答案
    return "E2";
  }
  e3Ready(): boolean {
    return this.awareness >= 70 && this.clues.size >= 6;
  }
}

export const director = CorruptionDirector.get();
