import type {
  ResearchHit,
  ScoutKnowledgeRelation,
  ScoutResearchNote,
  ScoutResearchTier,
} from "../domain/types";
import { mockDelay } from "./mockAi";
import { newId } from "./id";

const SOURCES = [
  { host: "www.commonhealth.com.tw", label: "康健雜誌" },
  { host: "www.edh.tw", label: "早安健康" },
  { host: "heho.com.tw", label: "Heho健康" },
  { host: "www.dcard.tw", label: "Dcard" },
  { host: "www.ptt.cc", label: "PTT" },
  { host: "medium.com", label: "Medium" },
];

export const RESEARCH_TIER_META: Record<
  ScoutResearchTier,
  { label: string; hint: string; order: number }
> = {
  core: { label: "最貼主題", hint: "直接對準痛點／關鍵語，優先讀", order: 0 },
  adjacent: { label: "相關周邊", hint: "鄰近情境，擴搜尋面", order: 1 },
  broad: { label: "最廣泛", hint: "背景與對照，選讀即可", order: 2 },
};

export const KNOWLEDGE_RELATION_META: Record<
  ScoutKnowledgeRelation,
  { label: string }
> = {
  solves_pain: { label: "對準痛點" },
  nearby_scene: { label: "鄰近場景" },
  myth: { label: "迷思澄清" },
  contrast: { label: "對照選購" },
  background: { label: "背景脈絡" },
};

function pageUrl(host: string, slug: string): string {
  return `https://${host}/article/${encodeURIComponent(slug)}`;
}

/** 漂亮顯示用：來源站名 + 精簡 host */
export function formatResearchLink(url: string, sourceLabel?: string): {
  label: string;
  host: string;
} {
  let host = "";
  try {
    host = new URL(url).hostname.replace(/^www\./, "");
  } catch {
    host = url.replace(/^https?:\/\//, "").split("/")[0] || "";
  }
  return {
    label: sourceLabel?.trim() || host || "來源",
    host,
  };
}

/**
 * 取得可顯示的學習重點（優先 learn_points；舊資料從 summary 拆）
 */
export function noteLearnPoints(n: Pick<ScoutResearchNote, "learn_points" | "summary">): string[] {
  if (n.learn_points && n.learn_points.length > 0) {
    return n.learn_points.slice(0, 5);
  }
  const raw = (n.summary || "").trim();
  if (!raw) return [];
  const byNum = raw
    .split(/(?=\d）)|(?=\d\.)|(?=；)/)
    .map((s) => s.replace(/^\d+[）.]\s*/, "").replace(/^；\s*/, "").trim())
    .filter((s) => s.length >= 8 && s.length <= 80);
  if (byNum.length >= 2) return byNum.slice(0, 4);
  const bySentence = raw
    .split(/[。！？\n]+/)
    .map((s) => s.trim())
    .filter((s) => s.length >= 8);
  return bySentence.slice(0, 3);
}

export function noteReplyHooks(n: Pick<ScoutResearchNote, "reply_hooks">): string[] {
  return (n.reply_hooks || []).filter(Boolean).slice(0, 3);
}

/**
 * mock 上網研究：標題 + 學習重點 + 回帖鉤子 + 摘要 + URL
 * 前幾則 core，後則 adjacent
 */
export async function mockWebResearch(query: string): Promise<ResearchHit[]> {
  await mockDelay(650);
  const q = query.trim() || "主題";
  const slug = q.replace(/\s+/g, "-").slice(0, 32) || "topic";

  const pages: Array<Omit<ResearchHit, "id">> = [
    {
      title: `${q}：常見迷思與實際差異`,
      snippet: `多數人討論「${q}」時會忽略使用情境，只看行銷字。`,
      learn_points: [
        `「溫和／天然」要對應使用頻率與膚況，不是萬能標籤`,
        `別只看成分表第一行，香精、防腐與殘留感也會刺`,
        `先寫自己的痛點句，再對規格，比問「哪個最好」準`,
      ],
      reply_hooks: [
        `先確認是刺鼻、刺癢還是洗不乾淨，三種解法不太一樣`,
        `無香也不等於一定不刺激，可以一起對成分表看`,
      ],
      summary: [
        `本篇整理「${q}」在公開討論中的三個常見誤區：`,
        `把「溫和／天然」當萬能標籤；只比成分表第一行；聽完業配再決策。`,
        `建議先寫下痛點句（刺鼻、刺癢、洗不乾淨），再回頭對規格。`,
      ].join(""),
      url: pageUrl(SOURCES[0]!.host, `${slug}-myths`),
      source_label: SOURCES[0]!.label,
      tier: "core",
    },
    {
      title: `專家觀點：如何評估 ${q}`,
      snippet: `可從安全性、長期成本、真實回饋三維度評估。`,
      learn_points: [
        `優先問：刺激來源能不能排除、有沒有可驗證使用情境`,
        `敏感或長時間接觸：先收集失敗案例，不要只看成功廣告`,
        `可操作三問：什麼會變糟？多久改善？有無生活替代？`,
      ],
      reply_hooks: [
        `你試過之後是「當下就刺」還是「用幾天後才不舒服」？`,
        `若目標是敏感肌，失敗案例通常比業配文更有參考價值`,
      ],
      summary: [
        `科普向文章：評估「${q}」時優先看刺激來源與使用情境。`,
        `問句可直接當 Threads 接話鉤子。`,
      ].join(""),
      url: pageUrl(SOURCES[1]!.host, `${slug}-howto`),
      source_label: SOURCES[1]!.label,
      tier: "core",
    },
    {
      title: `論壇實測串：${q} 用過的人怎麼說`,
      snippet: `公開討論裡「實際用過」的留言互動通常高於純規格文。`,
      learn_points: [
        `高頻抱怨：一用就刺鼻／刺癢、洗完有殘留、假無香`,
        `正向經驗多來自小範圍試用、對照香精欄、接受磨合期`,
        `海巡關鍵語：真的無香嗎、有人也刺痛嗎、求非業配`,
      ],
      reply_hooks: [
        `也有人一用就刺鼻，你是碰到味道還是接觸後刺癢？`,
        `論壇裡「求非業配」串通常比較敢講失敗經驗`,
      ],
      summary: [
        `彙整論壇約 40 則心得：抱怨集中在刺鼻、殘留、假無香。`,
        `回覆時先共感具體症狀，再輕提解法。`,
      ].join(""),
      url: pageUrl(SOURCES[3]!.host, `f-mood-${slug}-reviews`),
      source_label: SOURCES[3]!.label,
      tier: "adjacent",
    },
    {
      title: `${q} 對照表與選購清單（摘要）`,
      snippet: `把規格拆成痛點對照，比堆疊功能點更容易說服人。`,
      learn_points: [
        `拆成：刺激源、使用步驟、價格帶、適合誰／不適合誰`,
        `適合「已明確知道自己的雷」的人，不適合亂槍打鳥`,
        `對方痛點講清楚前，先不要急著丟產品連結`,
      ],
      reply_hooks: [
        `你比較在意「完全無味」還是「接觸後不刺」？兩個規格不一樣`,
        `若你已經知道自己的雷，對照表會比推薦清單好用`,
      ],
      summary: [
        `清單文把「${q}」拆成刺激源、步驟、價格、適合對象。`,
        `置入啟發：先確認痛點再決定要不要帶產品。`,
      ].join(""),
      url: pageUrl(SOURCES[2]!.host, `${slug}-checklist`),
      source_label: SOURCES[2]!.label,
      tier: "adjacent",
    },
  ];

  return pages.map((p) => ({ ...p, id: newId("hit") }));
}

export function formatResearchInsert(hits: ResearchHit[]): string {
  if (!hits.length) return "";
  return (
    "\n\n——\n（補充資料）\n" +
    hits
      .map((h, i) => {
        const points = h.learn_points?.length
          ? h.learn_points.map((p) => `· ${p}`).join("\n")
          : h.summary || h.snippet;
        const link = formatResearchLink(h.url, h.source_label);
        return `${i + 1}. ${h.title}\n${points}\n（${link.label} · ${link.host}）`;
      })
      .join("\n\n")
  );
}

function relationForTier(tier: ScoutResearchTier, title: string): ScoutKnowledgeRelation {
  if (title.includes("迷思")) return "myth";
  if (title.includes("對照") || title.includes("選購")) return "contrast";
  if (tier === "core") return "solves_pain";
  if (tier === "adjacent") return "nearby_scene";
  return "background";
}

/** ResearchHit → 海巡功課用的知識節點 */
export function researchHitsToScoutNotes(hits: ResearchHit[]): ScoutResearchNote[] {
  return hits.map((h) => {
    const tier = h.tier || "core";
    const summary = (h.summary || h.snippet || "").trim();
    const learn_points =
      h.learn_points && h.learn_points.length > 0
        ? h.learn_points
        : noteLearnPoints({ summary, learn_points: undefined });
    return {
      id: h.id,
      title: h.title,
      summary,
      learn_points,
      reply_hooks: h.reply_hooks?.length ? h.reply_hooks : undefined,
      url: h.url,
      source_label: h.source_label,
      keywords: extractKeywordsFromNote(h.title, h.summary || h.snippet),
      tier,
      relation: relationForTier(tier, h.title),
    };
  });
}

function extractKeywordsFromNote(title: string, body: string): string[] {
  const blob = `${title} ${body}`;
  const candidates = [
    "無香",
    "敏感肌",
    "刺鼻",
    "刺癢",
    "香精",
    "成分表",
    "溫和",
    "實測",
    "非業配",
    "插座",
    "第三空間",
    "久坐",
  ];
  const found = candidates.filter((k) => blob.includes(k));
  const head = title.split(/[：:]/)[0]?.trim();
  if (head && head.length >= 2 && head.length <= 16 && !found.includes(head)) {
    found.unshift(head.slice(0, 12));
  }
  return [...new Set(found)].slice(0, 5);
}

/**
 * 周邊詞 → 分層延伸頁
 * 前半 adjacent，後半 broad
 */
export async function mockExpandKnowledgePages(
  terms: string[],
  contextLabel?: string,
): Promise<ScoutResearchNote[]> {
  await mockDelay(350);
  const take = terms.filter(Boolean).slice(0, 6);
  return take.map((term, i) => {
    const src = SOURCES[(i + 2) % SOURCES.length]!;
    const ctx = contextLabel ? `（對齊 ${contextLabel}）` : "";
    const tier: ScoutResearchTier = i < 2 ? "adjacent" : "broad";
    if (tier === "broad") {
      return {
        id: newId("ek"),
        title: `背景：${term} 的更大討論脈絡${ctx}`,
        summary: `較廣角閱讀：「${term}」在生活／消費文化裡如何被框定。`,
        learn_points: [
          `「${term}」常被包進更大的生活／消費敘事，不只是單點規格`,
          `用途是聽懂對方從哪個場景開講，不是立刻給選品答案`,
          `語氣很散時：先接背景一句，再收斂到具體痛點`,
        ],
        reply_hooks: [
          `聽起來你是從「${term}」這條線在煩，我先對一下場景`,
        ],
        url: pageUrl(src.host, `expand-${term.slice(0, 16)}-${i + 1}`),
        source_label: src.label,
        keywords: [term],
        tier,
        relation: "background",
      };
    }
    return {
      id: newId("ek"),
      title: `周邊：${term} 為什麼常被一起談${ctx}`,
      summary: `針對關鍵語「${term}」的延伸摘要。`,
      learn_points: [
        `社群常把「${term}」和相鄰痛點綁在一起講`,
        `對方未必搜產品名，而是用症狀／場景說話`,
        `可帶走：用對方的詞接話 → 先釐清情境 → 再談規格`,
      ],
      reply_hooks: [
        `很多人提到「${term}」時，其實在講隔壁的痛，你是哪一種？`,
      ],
      url: pageUrl(src.host, `expand-${term.slice(0, 16)}-${i + 1}`),
      source_label: src.label,
      keywords: [term],
      tier,
      relation: "nearby_scene",
    };
  });
}

export function groupNotesByTier(
  notes: ScoutResearchNote[],
): { tier: ScoutResearchTier; notes: ScoutResearchNote[] }[] {
  const buckets: Record<ScoutResearchTier, ScoutResearchNote[]> = {
    core: [],
    adjacent: [],
    broad: [],
  };
  for (const n of notes) {
    const t = n.tier || "adjacent";
    buckets[t].push(n);
  }
  return (["core", "adjacent", "broad"] as ScoutResearchTier[])
    .filter((t) => buckets[t].length > 0)
    .map((tier) => ({ tier, notes: buckets[tier] }));
}
