import { prisma } from "@/lib/db";
import { getOrCreateSettings } from "@/lib/user-settings";
import { analyzeTopicIntent } from "@/lib/ai/analyze-topic";
import { parseProviderApiKeys } from "@/lib/ai/keys";
import { assertJobNotCancelled } from "@/lib/jobs/cancel";
import { updateJobProgress } from "@/lib/jobs/progress-server";
import type { JobProgressDetail } from "@/lib/jobs/types";
import { discoverSimilarAccounts } from "@/lib/services/discover-accounts";
import type { ResearchMap, SearchIntent } from "@/lib/types/research";
import { isPlacementGoal } from "@/lib/types/topic-goal";
import { normalizeUsername, parseSelectedTags } from "@/lib/types/research";
import { reconcileSelectedTags } from "@/lib/services/preserve-selected-tags";
import { pickDefaultSelectedTags } from "@/lib/services/scan-tasks";
import { getActiveAccount, refreshSession } from "@/lib/threads-browser";
import { resolvePersona } from "@/lib/db";
import { getActiveAccountProfile } from "@/lib/account-context";

async function withTimeout<T>(promise: Promise<T>, timeoutMs: number, label: string): Promise<T> {
  let timer: ReturnType<typeof setTimeout> | undefined;
  try {
    return await Promise.race([
      promise,
      new Promise<T>((_, reject) => {
        timer = setTimeout(() => reject(new Error(`${label}逾時`)), timeoutMs);
      }),
    ]);
  } finally {
    if (timer) clearTimeout(timer);
  }
}

function enrichTagsWithDiscoveredAccounts(map: ResearchMap): ResearchMap {
  const accounts = map.similarAccounts ?? [];
  if (accounts.length === 0) return map;

  const existing = new Set(
    map.suggestedTags.map((t) => normalizeUsername(t.tag).toLowerCase())
  );

  const accountTags = accounts
    .slice(0, 6)
    .filter((a) => !existing.has(a.username.toLowerCase()))
    .map((a) => ({
      tag: `@${a.username}`,
      reason: (a.reason || "網路搜尋找到的同領域帳號").slice(0, 80),
      searchIntent: "經驗" as SearchIntent,
      searchType: "帳號" as const,
    }));

  if (accountTags.length === 0) return map;

  return {
    ...map,
    suggestedTags: [...map.suggestedTags, ...accountTags].slice(0, 18),
  };
}

export async function analyzeTopic(
  topicId: string,
  briefOverride?: string | null,
  options?: {
    jobId?: string;
    onProgress?: (message: string) => void | Promise<void>;
  }
): Promise<ResearchMap> {
  const jobId = options?.jobId;
  const report = async (detail: JobProgressDetail) => {
    await options?.onProgress?.(detail.summary);
    if (jobId) await updateJobProgress(jobId, detail);
  };
  const topic = await prisma.topic.findUnique({ where: { id: topicId } });
  if (!topic) throw new Error("找不到主題");

  const brief =
    briefOverride !== undefined ? briefOverride?.trim() || null : topic.brief;

  if (briefOverride !== undefined) {
    await prisma.topic.update({
      where: { id: topicId },
      data: { brief },
    });
  }

  const settings = await getOrCreateSettings();
  const activeAccount = await getActiveAccountProfile();
  const apiKeys = parseProviderApiKeys(settings.providerApiKeys);

  const provider = settings.researchAiProvider ?? settings.aiProvider;
  const model = settings.researchAiModel ?? settings.aiModel;
  console.log(`[analyze-topic] start topic=${topicId} provider=${provider} model=${model}`);

  await report({
    summary: "AI 分析研究地圖中…",
    phase: "ai",
    tasks: [{ id: "ai", label: "AI 研究地圖", status: "running" }],
  });

  await assertJobNotCancelled(jobId);

  const baseMap = await analyzeTopicIntent({
    label: topic.label,
    query: topic.query,
    brief,
    productContext: topic.productContext,
    topicGoal: topic.topicGoal,
    persona: resolvePersona(settings, activeAccount),
    aiProvider: settings.researchAiProvider ?? settings.aiProvider,
    aiModel: settings.researchAiModel ?? settings.aiModel,
    apiKeys,
  });
  await assertJobNotCancelled(jobId);

  const placementMode = isPlacementGoal(topic.topicGoal);

  let similarAccounts: ResearchMap["similarAccounts"] = [];
  if (placementMode) {
    await report({
      summary: "AI 研究地圖完成（置入模式略過相似帳號）",
      phase: "ai",
      tasks: [{ id: "ai", label: "AI 研究地圖", status: "done" }],
    });
  } else {
    await report({
      summary: "AI 研究地圖完成，搜尋相似帳號中…",
      phase: "accounts",
      tasks: [
        { id: "ai", label: "AI 研究地圖", status: "done" },
        { id: "accounts", label: "搜尋相似帳號", status: "running" },
      ],
    });

    await assertJobNotCancelled(jobId);

    const account = await getActiveAccount().catch(() => null);
    let storageState: string | undefined;
    if (account) {
      const refreshed = await withTimeout(refreshSession(account), 20_000, "Threads Session 更新")
        .catch(() => null);
      if (refreshed?.valid) storageState = refreshed.storageState;
    }
    similarAccounts = await withTimeout(
      discoverSimilarAccounts({
        label: topic.label,
        query: topic.query,
        brief,
        productContext: topic.productContext,
        pillars: baseMap.pillars,
        suggestedTags: baseMap.suggestedTags.map((t) => t.tag),
        exclusions: baseMap.exclusions,
        storageState,
        limit: 8,
        aiProvider: provider,
        aiModel: model,
        apiKeys,
      }),
      90_000,
      "相似帳號搜尋"
    ).catch(async (error) => {
      console.warn(`[analyze-topic] similar account search skipped: ${String(error)}`);
      await report({
        summary: "研究地圖完成（相似帳號搜尋逾時，已略過）",
        phase: "accounts",
        tasks: [
          { id: "ai", label: "AI 研究地圖", status: "done" },
          { id: "accounts", label: "搜尋相似帳號（已略過）", status: "done" },
        ],
      });
      return [];
    });
    await assertJobNotCancelled(jobId);

    console.log(
      `[analyze-topic] discovered accounts=${similarAccounts.length} topic=${topicId}`
    );
    await report({
      summary: `AI 研究地圖完成 · 找到 ${similarAccounts.length} 個相似帳號`,
      phase: "accounts",
      tasks: [
        { id: "ai", label: "AI 研究地圖", status: "done" },
        { id: "accounts", label: "搜尋相似帳號", status: "done", found: similarAccounts.length },
      ],
    });
  }

  let researchMap: ResearchMap = { ...baseMap, similarAccounts };
  if (placementMode) {
    researchMap = {
      ...researchMap,
      similarAccounts: [],
      suggestedTags: researchMap.suggestedTags.filter(
        (t) => t.searchType !== "帳號" && !t.tag.startsWith("@")
      ),
    };
  } else {
    researchMap = enrichTagsWithDiscoveredAccounts(researchMap);
  }

  const existingSelected = parseSelectedTags(topic.selectedTags);
  const reconciled = reconcileSelectedTags(existingSelected, researchMap, {
    label: topic.label,
    query: topic.query,
    brief,
  });
  researchMap = reconciled.researchMap;

  const defaults = pickDefaultSelectedTags(researchMap, topic.topicGoal);
  const finalSelected = existingSelected.length > 0
      ? [...new Set([...reconciled.selectedTags, ...defaults])].slice(
          0,
          Math.max(6, Math.min(8, researchMap.suggestedTags.length))
        )
      : defaults;

  await assertJobNotCancelled(jobId);
  await prisma.topic.update({
    where: { id: topicId },
    data: {
      researchMap: JSON.stringify(researchMap),
      selectedTags: JSON.stringify(finalSelected),
    },
  });

  console.log(
    `[analyze-topic] done topic=${topicId} tags=${researchMap.suggestedTags.length} accounts=${similarAccounts.length}`
  );
  return researchMap;
}
