import type {
  Persona,
  PersonaDraftFields,
  PersonaGuard,
  PersonaStyle,
  StyleDimKey,
  StyleDimension,
} from "../domain/types";
import { nowUnixNano } from "./time";

export const DIM_ORDER: StyleDimKey[] = [
  "d1Tone",
  "d2Structure",
  "d3Interaction",
  "d4Topics",
  "d5Rhythm",
  "d6Visual",
  "d7Conversion",
  "d8Risk",
];

export const DIM_LABELS: Record<StyleDimKey, string> = {
  d1Tone: "D1 語氣人格",
  d2Structure: "D2 結構模板",
  d3Interaction: "D3 互動方式",
  d4Topics: "D4 主題分布",
  d5Rhythm: "D5 發文節奏",
  d6Visual: "D6 視覺語法",
  d7Conversion: "D7 轉換方式",
  d8Risk: "D8 風險紅線",
};

export type PersonaPromptMode = "post" | "reply" | "outreach" | "inspire";

export function emptyDraftFields(): PersonaDraftFields {
  return {
    identity: "",
    tone: "",
    audience: "",
    hooks: "",
    languageFingerprint: "",
    rhythm: "",
    punctuation: "",
    contentPatterns: "",
    knowledgeTranslation: "",
    ctaStyle: "",
    examples: "",
    avoid: "",
  };
}

export function emptyGuard(): PersonaGuard {
  return {
    avoid: ["硬廣", "客服腔", "條列說教"],
    maxChars: 280,
    banAiTone: true,
  };
}

export function emptyStyle(): PersonaStyle {
  return {
    dimensions: {},
    draft: emptyDraftFields(),
    draftText: "",
    source: "manual",
    sampleCount: 0,
  };
}

export function createEmptyPersona(partial?: Partial<Persona> & { id: string; name: string }): Persona {
  return {
    id: partial?.id || "",
    name: partial?.name || "",
    brief: partial?.brief || "",
    status: partial?.status || "empty",
    style: partial?.style || emptyStyle(),
    guard: partial?.guard || emptyGuard(),
    voice: partial?.voice,
    notes: partial?.notes,
  };
}

/** 把舊 name/voice/notes 人設升級成三層結構 */
export function normalizePersona(raw: Persona | Record<string, unknown>): Persona {
  const r = raw as Partial<Persona> & { voice?: string; notes?: string };
  const draft = {
    ...emptyDraftFields(),
    ...(r.style?.draft || {}),
  };
  if (!draft.tone && r.voice) draft.tone = r.voice;
  if (!draft.identity && r.name) draft.identity = r.name;
  if (!draft.avoid && r.notes) draft.avoid = r.notes;

  const style: PersonaStyle = {
    dimensions: r.style?.dimensions || {},
    draft,
    draftText: r.style?.draftText || (r.style ? serializeDraftText(draft) : ""),
    source: r.style?.source || "manual",
    sampleCount: r.style?.sampleCount || 0,
    analyzedAt: r.style?.analyzedAt,
  };

  if (!style.draftText && (draft.tone || draft.identity)) {
    style.draftText = serializeDraftText(draft);
  }

  const hasFingerprint = Boolean(style.draftText.trim()) || Object.keys(style.dimensions).length > 0;
  const status = r.status || (hasFingerprint ? "ready" : "empty");

  return {
    id: String(r.id || ""),
    name: String(r.name || "未命名人設"),
    brief: String(r.brief || r.notes || ""),
    status,
    style,
    guard: {
      ...emptyGuard(),
      ...(r.guard || {}),
      avoid: r.guard?.avoid?.length
        ? r.guard.avoid
        : emptyGuard().avoid,
    },
    voice: r.voice || draft.tone,
    notes: r.notes || r.brief,
  };
}

export function serializeDraftText(d: PersonaDraftFields): string {
  const lines: string[] = [];
  const push = (label: string, value: string) => {
    const v = value.trim();
    if (v) lines.push(`【${label}】\n${v}`);
  };
  push("我是誰", d.identity);
  push("語氣", d.tone);
  push("對誰說", d.audience);
  push("開場鉤子", d.hooks);
  push("語言指紋", d.languageFingerprint);
  push("節奏", d.rhythm);
  push("標點", d.punctuation);
  push("內容套路", d.contentPatterns);
  push("知識轉譯", d.knowledgeTranslation);
  push("CTA", d.ctaStyle);
  push("像他會說的話", d.examples);
  push("絕不怎麼說", d.avoid);
  return lines.join("\n\n");
}

export function toneOf(persona?: Persona | null): string {
  if (!persona) return "自然口語";
  return persona.style?.draft?.tone || persona.voice || "自然口語";
}

export function isPersonaReady(persona?: Persona | null): boolean {
  return persona?.status === "ready" && Boolean(persona.style?.draftText?.trim() || persona.style?.draft?.tone);
}

export function personaOptionLabel(persona: Persona): string {
  const tone = toneOf(persona);
  const badge = persona.status === "ready" ? "ready" : persona.status === "analyzing" ? "分析中" : "待分析";
  return `${persona.name} · ${tone}（${badge}）`;
}

/**
 * 依任務切片組裝人設 block。
 * mock / live 產文都應只吃這個字串。
 */
export function buildPersonaPromptBlock(persona: Persona | null | undefined, mode: PersonaPromptMode): string {
  if (!persona) {
    return "【人設】尚未選擇。請用台灣繁體、口語、像真人在 Threads 打字。";
  }

  const p = normalizePersona(persona);
  const parts: string[] = [];

  // Layer A — who
  if (mode === "post" || mode === "inspire" || mode === "outreach") {
    const who = [p.name && `名稱：${p.name}`, p.brief && `定位：${p.brief}`, p.style.draft.identity && `角色：${p.style.draft.identity}`]
      .filter(Boolean)
      .join("\n");
    if (who) parts.push(`【人設定位】\n${who}`);
  } else {
    // reply: light identity
    const light = p.style.draft.identity || p.name;
    if (light) parts.push(`【人設】你是「${light}」，用自己的語氣回覆。`);
  }

  // Layer B — how
  const draftText = p.style.draftText.trim() || serializeDraftText(p.style.draft);
  if (mode === "post") {
    if (draftText) parts.push(`【語言指紋與寫作規則】\n${draftText}`);
    const d2 = p.style.dimensions.d2Structure?.summary;
    const d4 = p.style.dimensions.d4Topics?.summary;
    if (d2 || d4) {
      parts.push(
        `【結構與主題重點】\n${[d2 && `結構：${d2}`, d4 && `主題：${d4}`].filter(Boolean).join("\n")}`,
      );
    }
  } else if (mode === "reply") {
    if (draftText) parts.push(`【語言指紋】\n${draftText}`);
    const d3 = p.style.dimensions.d3Interaction?.summary;
    if (d3) parts.push(`【互動方式】\n${d3}`);
  } else if (mode === "outreach") {
    const slim = [
      p.style.draft.tone && `語氣：${p.style.draft.tone}`,
      p.style.draft.avoid && `避免：${p.style.draft.avoid}`,
      p.style.draft.languageFingerprint && `用字：${p.style.draft.languageFingerprint}`,
      p.style.draft.ctaStyle && `收尾：${p.style.draft.ctaStyle}`,
    ]
      .filter(Boolean)
      .join("\n");
    if (slim) parts.push(`【外展語氣】\n${slim}`);
    else if (draftText) parts.push(`【語言指紋】\n${draftText}`);
  } else {
    // inspire
    const d4 = p.style.dimensions.d4Topics?.summary;
    const hooks = p.style.draft.hooks;
    const audience = p.style.draft.audience;
    parts.push(
      `【靈感方向】\n${[
        audience && `對誰：${audience}`,
        hooks && `鉤子：${hooks}`,
        d4 && `主題：${d4}`,
        p.style.draft.tone && `語氣：${p.style.draft.tone}`,
      ]
        .filter(Boolean)
        .join("\n") || draftText || p.brief}`,
    );
  }

  // Layer C — guard
  const avoid = [
    ...p.guard.avoid,
    ...(p.style.draft.avoid ? p.style.draft.avoid.split(/[、,，]/).map((s) => s.trim()).filter(Boolean) : []),
  ];
  const uniqAvoid = [...new Set(avoid)];
  const guardLines = [
    uniqAvoid.length ? `禁止：${uniqAvoid.join("、")}` : "",
    p.guard.banAiTone ? "禁止 AI 腔／客服腔／「總而言之」「希望這對您有幫助」" : "",
    p.guard.maxChars ? `長度約不超過 ${p.guard.maxChars} 字` : "",
    mode === "reply" ? "你是貼文作者本人在回，不要裝粉絲或官方帳號。" : "",
    mode === "outreach" ? "不硬廣；像過來人分享經驗，可輕輕帶觀點。" : "",
  ].filter(Boolean);
  if (guardLines.length) parts.push(`【護欄】\n${guardLines.join("\n")}`);

  // Light D1 + D8 always when available for post/reply
  if (mode === "post" || mode === "reply") {
    const d1 = p.style.dimensions.d1Tone?.summary;
    const d8 = p.style.dimensions.d8Risk?.summary;
    if (d1 || d8) {
      parts.push(
        `【語氣與禁忌參考】\n${[d1 && `語氣：${d1}`, d8 && `紅線：${d8}`].filter(Boolean).join("\n")}`,
      );
    }
  }

  return parts.join("\n\n") || `【人設】${p.name}：${toneOf(p)}`;
}

export function markReady(persona: Persona): Persona {
  const draftText = persona.style.draftText.trim() || serializeDraftText(persona.style.draft);
  return {
    ...persona,
    status: draftText ? "ready" : "empty",
    style: {
      ...persona.style,
      draftText,
      analyzedAt: persona.style.analyzedAt || nowUnixNano(),
    },
    voice: persona.style.draft.tone || persona.voice,
  };
}

export function dimSummary(persona: Persona, key: StyleDimKey): StyleDimension | undefined {
  return persona.style.dimensions[key];
}
