import { useEffect, useMemo, useState } from "react";
import { api, JobEvent, JobRun, JobSchedule } from "../api/haixun";
import { Badge, Button, Card, CopyableId, ErrorText, PageTitle } from "../components/ui";
import { formatNano } from "../lib/format";
import { canCancelJob, canRetryJob, ACTIVE_JOB_STATUSES } from "../lib/jobActions";
import { jobEventTypeLabel, jobPhaseLabel, jobStepStatusLabel, jobTemplateLabel, scheduleTemplateLabel } from "../lib/jobLabels";
import { jobStatusBadgeClass, jobStatusLabel } from "../lib/jobStatus";

type JobFilter = "all" | "active" | "failed" | "done";

const DONE_STATUSES = new Set(["succeeded", "completed", "cancelled", "expired"]);

function matchesFilter(job: JobRun, filter: JobFilter) {
  if (filter === "all") return true;
  if (filter === "active") return ACTIVE_JOB_STATUSES.has(job.status);
  if (filter === "failed") return job.status === "failed";
  if (filter === "done") return DONE_STATUSES.has(job.status);
  return true;
}

function JobErrorBlock({ error }: { error?: string }) {
  if (!error?.trim()) return null;
  return (
    <div
      style={{
        marginTop: "0.65rem",
        padding: "0.65rem 0.75rem",
        borderRadius: "var(--radius-md)",
        border: "1px solid color-mix(in srgb, var(--hx-danger) 35%, var(--hx-line))",
        background: "color-mix(in srgb, var(--hx-danger-soft) 55%, var(--hx-surface))",
        color: "var(--hx-ink)",
        fontSize: "0.85rem",
        lineHeight: 1.55,
        whiteSpace: "pre-wrap",
        wordBreak: "break-word"
      }}
    >
      <strong style={{ color: "var(--hx-danger)" }}>錯誤訊息</strong>
      <div style={{ marginTop: "0.35rem" }}>{error.trim()}</div>
    </div>
  );
}

function JobEventLog({ events, loading }: { events: JobEvent[]; loading: boolean }) {
  if (loading) {
    return <p className="muted hx-text-sm" style={{ margin: "0.5rem 0 0" }}>載入執行紀錄中…</p>;
  }
  if (events.length === 0) {
    return <p className="muted hx-text-sm" style={{ margin: "0.5rem 0 0" }}>沒有執行紀錄。</p>;
  }
  return (
    <div className="page-grid" style={{ gap: "0.45rem", marginTop: "0.65rem" }}>
      {events.map((event) => (
        <div
          key={event.id}
          style={{
            padding: "0.5rem 0.65rem",
            borderRadius: "var(--radius-sm)",
            border: "1px solid var(--hx-line)",
            background: "var(--hx-surface-muted)",
            fontSize: "0.8rem"
          }}
        >
          <div className="button-row" style={{ justifyContent: "space-between", flexWrap: "wrap", gap: "0.35rem" }}>
            <Badge variant="neutral">{jobEventTypeLabel(event.type)}</Badge>
            <span className="muted hx-text-sm">{formatNano(event.create_at)}</span>
          </div>
          {event.from || event.to ? (
            <p className="muted hx-text-sm" style={{ margin: "0.35rem 0 0" }}>
              {event.from ? jobStatusLabel(event.from) : "—"} → {event.to ? jobStatusLabel(event.to) : "—"}
            </p>
          ) : null}
          {event.message ? <p style={{ margin: "0.35rem 0 0", whiteSpace: "pre-wrap", wordBreak: "break-word" }}>{event.message}</p> : null}
        </div>
      ))}
    </div>
  );
}

function JobRow({
  job,
  expanded,
  events,
  eventsLoading,
  onToggle,
  onCancel,
  onRetry,
  actionLoading
}: {
  job: JobRun;
  expanded: boolean;
  events: JobEvent[];
  eventsLoading: boolean;
  onToggle: () => void;
  onCancel: () => void;
  onRetry: () => void;
  actionLoading: boolean;
}) {
  const steps = job.progress?.steps || [];
  const failedStep = steps.find((step) => step.status === "failed");

  return (
    <div
      className="mission-draft-card"
      style={{
        borderColor: job.status === "failed" ? "color-mix(in srgb, var(--hx-danger) 40%, var(--hx-line))" : undefined
      }}
    >
      <div className="mission-draft-copy">
        <div className="button-row" style={{ justifyContent: "space-between", flexWrap: "wrap", gap: "0.5rem" }}>
          <div>
            <strong>{jobTemplateLabel(job.template_type)}</strong>
            <p className="muted hx-text-sm" style={{ margin: "0.25rem 0 0" }}>
              {job.phase ? `階段：${jobPhaseLabel(job.phase)}` : "背景任務"}
              {job.worker_type ? ` · ${job.worker_type}` : ""}
            </p>
          </div>
          <Badge variant={jobStatusBadgeClass(job.status)}>{jobStatusLabel(job.status)}</Badge>
        </div>

        <div className="button-row" style={{ flexWrap: "wrap", gap: "0.5rem", marginTop: "0.5rem" }}>
          <span className="muted hx-text-sm">
            進度 {job.progress?.percentage ?? 0}%
            {job.progress?.summary ? ` · ${job.progress.summary}` : ""}
          </span>
          <span className="muted hx-text-sm">更新 {formatNano(job.update_at)}</span>
          {job.attempt && job.max_attempts ? (
            <span className="muted hx-text-sm">第 {job.attempt} / {job.max_attempts} 次</span>
          ) : null}
        </div>

        <JobErrorBlock error={job.error} />
        {!job.error?.trim() && failedStep?.message ? (
          <JobErrorBlock error={failedStep.message} />
        ) : null}

        {steps.length > 0 ? (
          <div style={{ marginTop: "0.55rem", display: "flex", flexWrap: "wrap", gap: "0.35rem" }}>
            {steps.map((step) => (
              <Badge key={step.id} variant={step.status === "failed" ? "danger" : step.status === "succeeded" ? "success" : "neutral"}>
                {jobPhaseLabel(step.id) || step.id}：{jobStepStatusLabel(step.status)}
              </Badge>
            ))}
          </div>
        ) : null}

        <div style={{ marginTop: "0.45rem" }}>
          <CopyableId value={job.id} />
        </div>

        <div className="button-row jobs-page-actions" style={{ flexWrap: "wrap", marginTop: "0.65rem" }}>
          <Button variant="soft" onClick={onToggle}>
            {expanded ? "收合紀錄" : "查看執行紀錄"}
          </Button>
          {canCancelJob(job) ? (
            <Button variant="danger" loading={actionLoading} onClick={onCancel}>取消任務</Button>
          ) : null}
          {canRetryJob(job) ? (
            <Button variant="primary" loading={actionLoading} onClick={onRetry}>重新執行</Button>
          ) : null}
        </div>

        {expanded ? <JobEventLog events={events} loading={eventsLoading} /> : null}
      </div>
    </div>
  );
}

export function JobsPage() {
  const [jobs, setJobs] = useState<JobRun[]>([]);
  const [schedules, setSchedules] = useState<JobSchedule[]>([]);
  const [error, setError] = useState<unknown>();
  const [loading, setLoading] = useState(false);
  const [filter, setFilter] = useState<JobFilter>("all");
  const [page, setPage] = useState(1);
  const [totalPages, setTotalPages] = useState(1);
  const [expandedId, setExpandedId] = useState("");
  const [eventsByJob, setEventsByJob] = useState<Record<string, JobEvent[]>>({});
  const [eventsLoadingId, setEventsLoadingId] = useState("");
  const [actionJobId, setActionJobId] = useState("");

  async function load(nextPage = page) {
    setLoading(true);
    setError(undefined);
    try {
      const [jobData, scheduleData] = await Promise.all([api.jobs(nextPage, 30), api.jobSchedules()]);
      setJobs(jobData.list || []);
      setPage(Number(jobData.pagination?.page || nextPage));
      setTotalPages(Number(jobData.pagination?.totalPages || 1));
      setSchedules(scheduleData.list || []);
    } catch (err) {
      setError(err);
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    void load(page);
    const timer = window.setInterval(() => void load(page), 5000);
    return () => window.clearInterval(timer);
  }, [page]);

  const filteredJobs = useMemo(() => jobs.filter((job) => matchesFilter(job, filter)), [jobs, filter]);

  const counts = useMemo(() => ({
    all: jobs.length,
    active: jobs.filter((j) => ACTIVE_JOB_STATUSES.has(j.status)).length,
    failed: jobs.filter((j) => j.status === "failed").length,
    done: jobs.filter((j) => DONE_STATUSES.has(j.status)).length
  }), [jobs]);

  async function toggleEvents(job: JobRun) {
    if (expandedId === job.id) {
      setExpandedId("");
      return;
    }
    setExpandedId(job.id);
    if (eventsByJob[job.id]) return;
    setEventsLoadingId(job.id);
    try {
      const data = await api.jobEvents(job.id, 50);
      setEventsByJob((prev) => ({ ...prev, [job.id]: data.list || [] }));
    } catch (err) {
      setError(err);
    } finally {
      setEventsLoadingId("");
    }
  }

  async function cancelJob(job: JobRun) {
    if (!window.confirm(`確定取消「${jobTemplateLabel(job.template_type)}」？`)) return;
    setActionJobId(job.id);
    try {
      await api.cancelJob(job.id);
      await load(page);
      window.dispatchEvent(new CustomEvent("haixun:jobs-refresh"));
    } catch (err) {
      setError(err);
    } finally {
      setActionJobId("");
    }
  }

  async function retryJob(job: JobRun) {
    setActionJobId(job.id);
    try {
      await api.retryJob(job.id);
      await load(page);
      window.dispatchEvent(new CustomEvent("haixun:jobs-refresh"));
    } catch (err) {
      setError(err);
    } finally {
      setActionJobId("");
    }
  }

  const filterButtons: Array<{ id: JobFilter; label: string; count: number }> = [
    { id: "all", label: "全部", count: counts.all },
    { id: "active", label: "進行中", count: counts.active },
    { id: "failed", label: "失敗", count: counts.failed },
    { id: "done", label: "已完成", count: counts.done }
  ];

  return (
    <div className="page-grid">
      <PageTitle
        title="任務中心"
        subtitle="查看背景任務進度、失敗原因與執行紀錄。失敗時請先展開「執行紀錄」，或看紅色錯誤區塊。"
        action={<Button loading={loading} onClick={() => void load(page)}>重新載入</Button>}
      />
      <ErrorText error={error} />

      <Card title="背景任務">
        <div className="page-grid">
          <div className="button-row" style={{ flexWrap: "wrap", gap: "0.45rem" }}>
            {filterButtons.map((item) => (
              <Button
                key={item.id}
                variant={filter === item.id ? "primary" : "soft"}
                onClick={() => setFilter(item.id)}
              >
                {item.label}（{item.count}）
              </Button>
            ))}
          </div>

          {filteredJobs.map((job) => (
            <JobRow
              key={job.id}
              job={job}
              expanded={expandedId === job.id}
              events={eventsByJob[job.id] || []}
              eventsLoading={eventsLoadingId === job.id}
              onToggle={() => void toggleEvents(job)}
              onCancel={() => void cancelJob(job)}
              onRetry={() => void retryJob(job)}
              actionLoading={actionJobId === job.id}
            />
          ))}

          {filteredJobs.length === 0 && !loading ? (
            <p className="muted">這個篩選下目前沒有任務。可以去文案任務頁產生草稿，或到找 Ta 頁啟動海巡。</p>
          ) : null}

          <div className="button-row" style={{ justifyContent: "center" }}>
            <Button disabled={page <= 1 || loading} onClick={() => setPage((value) => Math.max(1, value - 1))}>上一頁</Button>
            <span className="muted">{page} / {totalPages}</span>
            <Button disabled={page >= totalPages || loading} onClick={() => setPage((value) => value + 1)}>下一頁</Button>
          </div>
        </div>
      </Card>

      <Card title="週期排程">
        <div className="table-wrap">
          <table>
            <thead>
              <tr>
                <th>任務類型</th>
                <th>排程規則</th>
                <th>時區</th>
                <th>狀態</th>
                <th>下次執行</th>
              </tr>
            </thead>
            <tbody>
              {schedules.map((schedule) => (
                <tr key={schedule.id}>
                  <td>{scheduleTemplateLabel(schedule.template_type)}</td>
                  <td><code>{schedule.cron}</code></td>
                  <td>{schedule.timezone || "UTC"}</td>
                  <td><Badge variant={schedule.enabled ? "success" : "neutral"}>{schedule.enabled ? "啟用" : "停用"}</Badge></td>
                  <td>{schedule.next_run_at ? formatNano(schedule.next_run_at) : "—"}</td>
                </tr>
              ))}
            </tbody>
          </table>
          {schedules.length === 0 ? <p className="muted">目前沒有週期排程。</p> : null}
        </div>
      </Card>
    </div>
  );
}