"use client";

import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useRef,
  useState,
  type ReactNode,
} from "react";
import { JOB_LABELS, type JobStatus } from "@/lib/jobs/types";
import { notify } from "@/lib/notifications/store";
import { parseFetchJson } from "@/lib/utils";

export interface BackgroundJobItem {
  id: string;
  type: string;
  status: JobStatus;
  accountId?: string | null;
  topicId?: string | null;
  label?: string | null;
  progress?: string | null;
  progressDetail?: string | null;
  error?: string | null;
  result?: string | null;
  createdAt: string;
  completedAt?: string | null;
}

export interface LatestToast {
  title: string;
  message?: string;
  href?: string;
  type: "success" | "error" | "info" | "warning";
}

interface JobsContextValue {
  jobs: BackgroundJobItem[];
  activeJobs: BackgroundJobItem[];
  latestToast: LatestToast | null;
  dismissToast: () => void;
  cancelJob: (jobId: string) => Promise<boolean>;
  cancellingId: string | null;
  refreshJobs: () => Promise<void>;
}

const JobsContext = createContext<JobsContextValue | null>(null);

function buildScanCompleteMessage(
  result: string | null | undefined,
  progress?: string | null
): string | undefined {
  if (progress && progress.startsWith("完成 ·")) return progress;

  try {
    const scan = JSON.parse(result ?? "{}") as {
      items?: unknown[];
      repliesFetched?: boolean;
      repliesCount?: number;
    };
    const total = scan.items?.length ?? 0;
    if (total === 0) return undefined;

    const replyPart = scan.repliesFetched
      ? `${scan.repliesCount ?? 0} 則留言 · `
      : "未抓留言 · ";

    return `${replyPart}共 ${total} 篇`;
  } catch {
    return undefined;
  }
}

export function JobsProvider({ children }: { children: ReactNode }) {
  const [jobs, setJobs] = useState<BackgroundJobItem[]>([]);
  const [latestToast, setLatestToast] = useState<LatestToast | null>(null);
  const [cancellingId, setCancellingId] = useState<string | null>(null);
  const notifiedRef = useRef<Set<string>>(new Set());
  const initializedRef = useRef(false);

  const dismissToast = useCallback(() => setLatestToast(null), []);

  const refreshJobs = useCallback(async () => {
    let list: BackgroundJobItem[] = [];
    try {
      const res = await fetch("/api/jobs?limit=12");
      const data = await parseFetchJson<{ jobs?: BackgroundJobItem[] }>(res);
      if (!res.ok) return;
      list = data.jobs ?? [];
    } catch {
      return;
    }
    setJobs(list);

    if (!initializedRef.current) {
      for (const job of list) {
        if (job.status === "completed" || job.status === "failed" || job.status === "cancelled") {
          notifiedRef.current.add(job.id);
        }
      }
      initializedRef.current = true;
      return;
    }

    for (const job of list) {
      if (
        (job.status === "completed" || job.status === "failed" || job.status === "cancelled") &&
        !notifiedRef.current.has(job.id)
      ) {
        notifiedRef.current.add(job.id);
        const name = job.label ?? JOB_LABELS[job.type as keyof typeof JOB_LABELS] ?? job.type;
        window.dispatchEvent(new CustomEvent("job-completed", { detail: { job } }));

        if (job.status === "completed") {
          if (job.type === "analyze-topic") {
            const toast: LatestToast = {
              type: "success",
              title: `${name} 已完成`,
              href: job.topicId ? `/scans/${job.topicId}` : "/scans",
            };
            setLatestToast(toast);
            notify(toast);
          }
          if (job.type === "scan") {
            const message = buildScanCompleteMessage(job.result, job.progress);
            const toast: LatestToast = {
              type: "success",
              title: "海巡完成",
              message,
              href: job.topicId ? `/scans/${job.topicId}/results` : "/scans",
            };
            setLatestToast(toast);
            notify(toast);
          }
          if (job.type === "style-8d") {
            const toast: LatestToast = {
              type: "success",
              title: "帳號 8D 分析完成",
              message: job.progress ?? "8D 策略已儲存並套用",
              href: "/accounts",
            };
            setLatestToast(toast);
            notify(toast);
          }
          if (job.type === "ai-task") {
            const toast: LatestToast = {
              type: "success",
              title: `${name}完成`,
            };
            setLatestToast(toast);
            notify(toast);
          }
        } else if (job.status === "cancelled") {
          const toast: LatestToast = {
            type: "info",
            title: `${name} 已停止`,
            href: job.type === "style-8d" ? "/accounts" : job.topicId ? `/scans/${job.topicId}` : "/notifications",
          };
          setLatestToast(toast);
          notify(toast);
        } else if (job.status === "failed") {
          const toast: LatestToast = {
            type: "error",
            title: `${name} 失敗`,
            message: job.error ?? "未知錯誤",
            href: job.type === "style-8d" ? "/accounts" : job.topicId ? `/scans/${job.topicId}` : "/notifications",
          };
          setLatestToast(toast);
          notify(toast);
        }
      }
    }
  }, []);

  useEffect(() => {
    refreshJobs();
    const timer = window.setInterval(refreshJobs, 2000);
    const refreshImmediately = () => void refreshJobs();
    window.addEventListener("haixun:jobs-updated", refreshImmediately);
    return () => {
      window.clearInterval(timer);
      window.removeEventListener("haixun:jobs-updated", refreshImmediately);
    };
  }, [refreshJobs]);

  useEffect(() => {
    if (!latestToast) return;
    const timer = window.setTimeout(() => setLatestToast(null), 8000);
    return () => window.clearTimeout(timer);
  }, [latestToast]);

  const cancelJob = useCallback(
    async (jobId: string) => {
      setCancellingId(jobId);
      try {
        const res = await fetch(`/api/jobs/${jobId}/cancel`, { method: "POST" });
        const data = await res.json();
        if (!res.ok) {
          notify({ type: "error", title: "停止失敗", message: data.error });
          return false;
        }
        await refreshJobs();
        return true;
      } finally {
        setCancellingId(null);
      }
    },
    [refreshJobs]
  );

  const activeJobs = useMemo(
    () => jobs.filter((j) => j.status === "pending" || j.status === "running"),
    [jobs]
  );

  const value = useMemo(
    () => ({
      jobs,
      activeJobs,
      latestToast,
      dismissToast,
      cancelJob,
      cancellingId,
      refreshJobs,
    }),
    [jobs, activeJobs, latestToast, dismissToast, cancelJob, cancellingId, refreshJobs]
  );

  return <JobsContext.Provider value={value}>{children}</JobsContext.Provider>;
}

export function useJobs() {
  const ctx = useContext(JobsContext);
  if (!ctx) throw new Error("useJobs must be used within JobsProvider");
  return ctx;
}
