import { useCallback, useEffect, useRef, useState } from "react";
import { api, JobRun } from "../api/haixun";
import { Badge, Button } from "./ui";
import { formatNano } from "../lib/format";
import { canCancelJob, canRetryJob } from "../lib/jobActions";
import { jobTemplateLabel } from "../lib/jobLabels";
import { jobStatusBadgeClass, jobStatusLabel } from "../lib/jobStatus";
import { AcIcon } from "./AcIcon";
import type { JobCreatedDetail } from "../lib/jobEvents";

const ACTIVE_STATUSES = ["running", "queued", "pending", "waiting_worker", "cancel_requested"];
const PANEL_STATUSES = [...ACTIVE_STATUSES, "failed"];

function nowNano() {
  return Date.now() * 1_000_000;
}

function optimisticJob(detail: JobCreatedDetail): JobRun {
  return {
    id: detail.jobId,
    template_type: detail.templateType || detail.label || "任務",
    status: detail.status || "queued",
    progress: { percentage: 0, summary: "剛建立，等待執行…" },
    create_at: nowNano(),
    update_at: nowNano()
  };
}

function JobMonitorItem({
  job,
  actionLoading,
  onCancel,
  onRetry,
  showError
}: {
  job: JobRun;
  actionLoading: boolean;
  onCancel: () => void;
  onRetry: () => void;
  showError: boolean;
}) {
  return (
    <div
      className="job-panel-item"
      style={{
        border: `1px solid ${job.status === "failed" ? "color-mix(in srgb, var(--hx-danger) 40%, var(--hx-line))" : "var(--hx-line)"}`,
        borderRadius: "var(--radius-md)",
        padding: "0.55rem 0.7rem",
        marginBottom: "0.5rem",
        background: "var(--hx-surface)"
      }}
    >
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "0.25rem" }}>
        <strong style={{ fontSize: "0.9rem" }}>{jobTemplateLabel(job.template_type)}</strong>
        <Badge variant={jobStatusBadgeClass(job.status)}>{jobStatusLabel(job.status)}</Badge>
      </div>

      {job.progress ? (
        <div style={{ fontSize: "0.8rem", color: "var(--hx-ink-secondary)", marginBottom: "0.2rem" }}>
          {job.progress.percentage ?? 0}%
          {job.progress.summary ? ` · ${job.progress.summary}` : ""}
        </div>
      ) : null}

      {showError && job.error?.trim() ? (
        <div
          style={{
            fontSize: "0.78rem",
            color: "var(--hx-danger)",
            marginBottom: "0.35rem",
            whiteSpace: "pre-wrap",
            wordBreak: "break-word",
            lineHeight: 1.45
          }}
        >
          {job.error.trim()}
        </div>
      ) : null}

      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: "0.35rem", fontSize: "0.72rem", flexWrap: "wrap" }}>
        <span className="muted">{formatNano(job.update_at)}</span>
        <div className="button-row" style={{ gap: "0.35rem" }}>
          {canCancelJob(job) ? (
            <Button
              variant="danger"
              onClick={onCancel}
              loading={actionLoading}
              style={{ fontSize: "0.7rem", padding: "0.15rem 0.5rem", minHeight: "1.6rem" }}
            >
              取消
            </Button>
          ) : null}
          {canRetryJob(job) ? (
            <Button
              variant="primary"
              onClick={onRetry}
              loading={actionLoading}
              style={{ fontSize: "0.7rem", padding: "0.15rem 0.5rem", minHeight: "1.6rem" }}
            >
              重作
            </Button>
          ) : null}
        </div>
      </div>
    </div>
  );
}

export function JobMonitor() {
  const [jobs, setJobs] = useState<JobRun[]>([]);
  const [open, setOpen] = useState(false);
  const [actionJobId, setActionJobId] = useState("");
  const [hot, setHot] = useState(false);
  const pendingRef = useRef<Map<string, JobRun>>(new Map());

  const mergeWithPending = useCallback((serverList: JobRun[]) => {
    const serverIds = new Set(serverList.map((j) => j.id));
    for (const id of [...pendingRef.current.keys()]) {
      if (serverIds.has(id)) pendingRef.current.delete(id);
    }
    const pending = [...pendingRef.current.values()].filter((j) => !serverIds.has(j.id));
    return [...pending, ...serverList];
  }, []);

  const load = useCallback(async () => {
    try {
      const data = await api.jobs(1, 20);
      setJobs(mergeWithPending(data.list || []));
    } catch {
      // 背景浮層靜默失敗，完整錯誤到任務中心看
    }
  }, [mergeWithPending]);

  const burstRefresh = useCallback(() => {
    void load();
    window.setTimeout(() => void load(), 350);
    window.setTimeout(() => void load(), 900);
    window.setTimeout(() => void load(), 1800);
  }, [load]);

  useEffect(() => {
    void load();
  }, [load]);

  const panelJobs = jobs.filter((j) => PANEL_STATUSES.includes(j.status));
  const activeJobs = panelJobs.filter((j) => ACTIVE_STATUSES.includes(j.status));
  const failedJobs = panelJobs.filter((j) => j.status === "failed").slice(0, 3);
  const hasActive = activeJobs.length > 0;
  const hasFailed = failedJobs.length > 0;

  useEffect(() => {
    const intervalMs = hasActive ? 1000 : 4500;
    const timer = window.setInterval(() => void load(), intervalMs);
    return () => window.clearInterval(timer);
  }, [hasActive, load]);

  useEffect(() => {
    function onJobCreated(event: Event) {
      const detail = (event as CustomEvent<JobCreatedDetail>).detail;
      if (!detail?.jobId) return;
      const job = optimisticJob(detail);
      pendingRef.current.set(detail.jobId, job);
      setJobs((prev) => {
        if (prev.some((j) => j.id === detail.jobId)) return prev;
        return [job, ...prev];
      });
      setOpen(true);
      setHot(true);
      burstRefresh();
      window.setTimeout(() => setHot(false), 2400);
    }

    function onRefresh() {
      burstRefresh();
    }

    window.addEventListener("haixun:job-created", onJobCreated);
    window.addEventListener("haixun:jobs-refresh", onRefresh);
    return () => {
      window.removeEventListener("haixun:job-created", onJobCreated);
      window.removeEventListener("haixun:jobs-refresh", onRefresh);
    };
  }, [burstRefresh]);

  async function cancel(job: JobRun) {
    setActionJobId(job.id);
    try {
      await api.cancelJob(job.id);
      pendingRef.current.delete(job.id);
      await load();
      window.dispatchEvent(new CustomEvent("haixun:jobs-refresh"));
    } catch {
      // 錯誤細節到任務中心看
    } finally {
      setActionJobId("");
    }
  }

  async function retry(job: JobRun) {
    setActionJobId(job.id);
    try {
      await api.retryJob(job.id);
      pendingRef.current.delete(job.id);
      await load();
      window.dispatchEvent(new CustomEvent("haixun:jobs-refresh"));
    } catch {
      // 錯誤細節到任務中心看
    } finally {
      setActionJobId("");
    }
  }

  const count = activeJobs.length;

  return (
    <>
      <button
        onClick={() => setOpen(!open)}
        className={`job-fab${hot || count > 0 || hasFailed ? " job-fab--hot" : ""}`}
        style={{
          position: "fixed",
          bottom: "calc(4.5rem + env(safe-area-inset-bottom, 0px))",
          right: "1rem",
          zIndex: 110,
          background: count > 0 || hasFailed ? "var(--hx-brand)" : "var(--hx-surface-muted)",
          color: count > 0 || hasFailed ? "white" : "var(--hx-muted)",
          border: count > 0 || hasFailed ? "none" : "1px solid var(--hx-line)",
          borderRadius: "999px",
          padding: "0.4rem 0.85rem",
          fontSize: "0.78rem",
          fontWeight: 700,
          display: "flex",
          alignItems: "center",
          gap: "0.4rem",
          boxShadow: "var(--shadow-card)",
          cursor: "pointer"
        }}
        title={count > 0 ? `${count} 個任務進行中` : hasFailed ? "有任務失敗" : "查看任務狀態"}
      >
        <AcIcon name="job" size={17} />
        <span>
          {count > 0 ? `${count} 進行中` : hasFailed ? "有失敗" : "任務"}
        </span>
      </button>

      {open && (
        <div
          className="job-panel"
          style={{
            position: "fixed",
            bottom: "calc(6.5rem + env(safe-area-inset-bottom, 0px))",
            right: "1rem",
            zIndex: 120,
            width: "min(360px, calc(100vw - 2rem))",
            maxHeight: "58vh",
            background: "var(--hx-surface)",
            border: "1px solid var(--hx-line)",
            borderRadius: "var(--radius-lg)",
            boxShadow: "var(--shadow-card)",
            display: "flex",
            flexDirection: "column",
            overflow: "hidden"
          }}
        >
          <div
            style={{
              display: "flex",
              alignItems: "center",
              justifyContent: "space-between",
              padding: "0.6rem 0.85rem",
              borderBottom: "1px solid var(--hx-line)",
              background: "var(--hx-surface-muted)"
            }}
          >
            <div style={{ fontWeight: 700, display: "flex", alignItems: "center", gap: "0.4rem" }}>
              <AcIcon name="job" size={16} />
              任務狀態 {count > 0 ? `（${count} 進行中）` : ""}
            </div>
            <button
              onClick={() => setOpen(false)}
              style={{ background: "transparent", border: "none", fontSize: "1.1rem", lineHeight: 1, cursor: "pointer", color: "var(--hx-muted)" }}
              aria-label="關閉"
            >
              ×
            </button>
          </div>

          <div style={{ overflowY: "auto", padding: "0.5rem", flex: 1 }}>
            {activeJobs.length === 0 && failedJobs.length === 0 ? (
              <p className="muted" style={{ padding: "0.5rem 0.3rem" }}>目前沒有進行中或失敗的任務。</p>
            ) : null}

            {activeJobs.map((job) => (
              <JobMonitorItem
                key={job.id}
                job={job}
                actionLoading={actionJobId === job.id}
                onCancel={() => void cancel(job)}
                onRetry={() => void retry(job)}
                showError={false}
              />
            ))}

            {failedJobs.length > 0 ? (
              <>
                <p className="muted hx-text-sm" style={{ margin: "0.35rem 0.15rem 0.45rem", fontWeight: 700 }}>最近失敗</p>
                {failedJobs.map((job) => (
                  <JobMonitorItem
                    key={job.id}
                    job={job}
                    actionLoading={actionJobId === job.id}
                    onCancel={() => void cancel(job)}
                    onRetry={() => void retry(job)}
                    showError
                  />
                ))}
              </>
            ) : null}
          </div>

          <div style={{ padding: "0.4rem 0.7rem", borderTop: "1px solid var(--hx-line)", background: "var(--hx-surface-muted)" }}>
            <Button
              onClick={() => {
                window.location.hash = "jobs";
                setOpen(false);
              }}
              style={{ width: "100%", fontSize: "0.75rem" }}
            >
              前往任務中心看完整紀錄
            </Button>
          </div>
        </div>
      )}
    </>
  );
}