import type { Persona, PersonaDraftFields, StyleDimKey, StyleDimension } from "../domain/types";
import { mockDelay } from "./mockAi";
import {
  emptyDraftFields,
  emptyGuard,
  normalizePersona,
  serializeDraftText,
} from "./personaPrompt";
import { nowUnixNano } from "./time";

export function splitSamples(raw: string): string[] {
  return raw
    .split(/\n\s*---\s*\n|\n{3,}/)
    .map((s) => s.trim())
    .filter((s) => s.length >= 10)
    .slice(0, 12);
}

function pickEvidence(samples: string[], max = 2): string[] {
  return samples
    .map((s) => (s.length > 36 ? `${s.slice(0, 36)}…` : s))
    .slice(0, max);
}

function inferTone(blob: string): string {
  if (/哈哈|笑死|哭|靠|真的假的/.test(blob)) return "輕鬆吐槽、情緒外露";
  if (/建議|成分|數據|對比|規格/.test(blob)) return "務實、有依據、少廢話";
  if (/懂|抱抱|辛苦|没关系|沒關係|一起/.test(blob)) return "共感、溫柔、像朋友";
  return "口語親近、不端著";
}

function inferHooks(blob: string): string {
  if (/？|\?/.test(blob)) return "用真心疑問開場，邀請別人補經驗";
  if (/有人|大家|求/.test(blob)) return "先丟痛點再求推坑／經驗";
  return "先講自己卡關的情境，再拋問題";
}

export type AnalyzeSource =
  | { kind: "manual"; label?: string }
  | { kind: "benchmark"; username: string };

/**
 * Mock：模擬爬取公開 Threads 貼文（接真後改 Playwright / API）。
 */
export async function mockScrapePublicPosts(username: string): Promise<string[]> {
  const handle = username.replace(/^@/, "").trim().toLowerCase();
  if (!handle || handle.length < 2) {
    throw new Error("請輸入有效的 Threads username（不含網址）");
  }
  if (/[\s/]/.test(handle)) {
    throw new Error("username 請只填帳號，例如 ultralab_tw");
  }

  // 模擬網路延遲（爬公開頁）
  await mockDelay(900);

  // 依 username 長出可辨識差異的假樣本，讓分析結果不像隨機
  const isFun = /fun|meme|laugh|吐|梗/.test(handle);
  const isPro = /lab|pro|tech|care|skin|official/.test(handle);

  if (isFun) {
    return [
      `不是我不想研究，是 @${handle} 看規格表看到想睡…有人也這樣嗎？`,
      `講真的上次踩雷之後我都先問「實際用起來」再下單，規格文先放旁邊。`,
      `笑死剛看到有人寫「無痛入手」，結果後來留言區全是後悔文。`,
      `你們週末都在幹嘛，我還在跟自己的購物車吵架。`,
    ];
  }
  if (isPro) {
    return [
      `若你在意耐用，我會先看使用情境再對規格；同樣標示差很多。`,
      `建議把需求拆成：頻率、膚況／環境、預算三欄，再對產品會比較準。`,
      `成分表先找會刺鼻或致敏的那幾欄；有疑慮再問實際使用者。`,
      `對比兩款時不要只看行銷字，看「你會每天碰到的那一段流程」。`,
    ];
  }
  return [
    `有時候真的會卡在「不知道問誰」——後來我改成先寫自己的使用情境。`,
    `懂那種越研究越焦慮的感覺。我通常先問有沒有實際用過、會不會踩雷。`,
    `大家如果有推的，最好附一句為什麼，比空推一個名字有用。`,
    `我自己目前是先抓痛點再對規格，不是一開始就掃整張規格表。`,
    `你們呢？有類似經驗也可以講，我想整理給之後的自己。`,
  ];
}

function analyzeFromSamples(
  persona: Persona,
  samples: string[],
  source: AnalyzeSource,
): Persona {
  if (samples.length < 2) {
    throw new Error("樣本不足（至少 2 則公開貼文／參考段）");
  }

  const blob = samples.join("\n");
  const evidence = pickEvidence(samples);
  const tone = inferTone(blob);
  const hooks = inferHooks(blob);
  const base = normalizePersona(persona);
  const label =
    source.kind === "benchmark"
      ? `@${source.username.replace(/^@/, "")}`
      : source.label?.trim() || "手動貼文";

  const draft: PersonaDraftFields = {
    ...emptyDraftFields(),
    identity: base.style.draft.identity || base.name || "生活觀察者",
    tone,
    audience: base.style.draft.audience || "同溫層、會在 Threads 求經驗的人",
    hooks,
    languageFingerprint: /有時候|後來|其實|講真的/.test(blob)
      ? "常用「有時候／後來／其實」當轉折"
      : "短句、口語、少成語",
    rhythm: blob.includes("\n") ? "2～4 個短段落，段間空行" : "一段講完再補一句問句",
    punctuation: /…|\.\.\./.test(blob) ? "愛用省略號與問號" : "逗號與問號為主，少驚嘆",
    contentPatterns: "情境 → 感受或觀察 → 輕問一句",
    knowledgeTranslation: "先講使用情境，再講重點，不丟術語牆",
    ctaStyle: "自然邀留言（「你們呢」「有人也…嗎」），不命令",
    examples: samples[0].slice(0, 80),
    avoid: base.style.draft.avoid || "硬銷、條列教學、客服腔、假裝中立實則業配",
  };

  const dim = (summary: string, ev = evidence): StyleDimension => ({ summary, evidence: ev });

  const dimensions: Partial<Record<StyleDimKey, StyleDimension>> = {
    d1Tone: dim(tone),
    d2Structure: dim("開場情境 → 中段補充 → 結尾提問或輕 CTA"),
    d3Interaction: dim("接住對方情緒後再給觀點；回覆用提問延續對話"),
    d4Topics: dim(base.brief || `生活經驗（樣本：${label}）`, evidence.slice(0, 1)),
    d5Rhythm: dim(draft.rhythm),
    d6Visual: dim(draft.punctuation + "；少 emoji 或 0～1 個"),
    d7Conversion: dim(draft.ctaStyle),
    d8Risk: dim(draft.avoid, []),
  };

  const draftText = serializeDraftText(draft);
  const avoidList = draft.avoid
    .split(/[、,，]/)
    .map((s) => s.trim())
    .filter(Boolean);

  return {
    ...base,
    brief: base.brief || `${tone}；對「${draft.audience}」說話`,
    status: "ready",
    voice: draft.tone,
    notes: base.brief,
    style: {
      dimensions,
      draft,
      draftText,
      source: source.kind === "benchmark" ? "benchmark" : "manual",
      benchmarkUsername: source.kind === "benchmark" ? source.username.replace(/^@/, "") : undefined,
      sourceLabel: source.kind === "manual" ? label : undefined,
      sampleCount: samples.length,
      samplePreviews: samples.slice(0, 5).map((s) => (s.length > 100 ? `${s.slice(0, 100)}…` : s)),
      analyzedAt: nowUnixNano(),
    },
    guard: {
      ...emptyGuard(),
      ...base.guard,
      avoid: avoidList.length ? avoidList : emptyGuard().avoid,
      banAiTone: true,
      maxChars: base.guard?.maxChars || 280,
    },
  };
}

/**
 * 從貼上文字分析（手動樣本）。
 */
export async function mockAnalyzePersonaFromText(
  persona: Persona,
  rawText: string,
  sourceLabel?: string,
): Promise<Persona> {
  await mockDelay(500);
  const samples = splitSamples(rawText);
  if (samples.length < 2) {
    throw new Error("請至少貼 2 段參考文字（可用 --- 分隔），每段至少約 10 字");
  }
  return analyzeFromSamples(persona, samples, { kind: "manual", label: sourceLabel });
}

/**
 * 從公開帳號爬貼文再分析（mock 爬取）。
 */
export async function mockAnalyzePersonaFromAccount(
  persona: Persona,
  username: string,
): Promise<{ persona: Persona; posts: string[] }> {
  const handle = username.replace(/^@/, "").trim();
  const posts = await mockScrapePublicPosts(handle);
  // 分析階段
  await mockDelay(600);
  const next = analyzeFromSamples(persona, posts, { kind: "benchmark", username: handle });
  return { persona: next, posts };
}

export function buildSeedReadyStyle(opts: {
  identity: string;
  tone: string;
  audience: string;
  examples: string;
  avoid?: string;
}): Persona["style"] {
  const draft: PersonaDraftFields = {
    identity: opts.identity,
    tone: opts.tone,
    audience: opts.audience,
    hooks: "先丟真實卡關，再問一句",
    languageFingerprint: "口語、短句、偶爾「其實／有時候」",
    rhythm: "2～3 短段，段間空行",
    punctuation: "問號收尾，少驚嘆",
    contentPatterns: "痛點 → 自己經驗 → 輕問",
    knowledgeTranslation: "用生活例子講，不丟規格表",
    ctaStyle: "「有人也這樣嗎」",
    examples: opts.examples,
    avoid: opts.avoid || "硬廣、說教、AI 腔",
  };
  const dim = (summary: string): StyleDimension => ({ summary, evidence: [opts.examples.slice(0, 40)] });
  return {
    dimensions: {
      d1Tone: dim(opts.tone),
      d2Structure: dim("情境開場 → 經驗 → 提問"),
      d3Interaction: dim("先接話再補觀點"),
      d4Topics: dim("生活選品與真實經驗"),
      d5Rhythm: dim(draft.rhythm),
      d6Visual: dim("換行分段，少 emoji"),
      d7Conversion: dim(draft.ctaStyle),
      d8Risk: dim(draft.avoid),
    },
    draft,
    draftText: serializeDraftText(draft),
    source: "seed",
    sampleCount: 3,
    analyzedAt: nowUnixNano(),
  };
}
