import { RotateCcw } from "lucide-react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { Link, useParams } from "react-router-dom";
import { toast } from "sonner";

import { api } from "../api";
import { eventTitle } from "../constants";
import { DateTime } from "../components/DateTime";
import { EmptyState } from "../components/EmptyState";
import { StatusBadge } from "../components/StatusBadge";
import type { Job, JobEvent } from "../types";

type TimelineEvent = JobEvent & {
  firstId: number;
  lastId: number;
  repeatCount: number;
};

function buildTimeline(events: JobEvent[]) {
  const grouped: TimelineEvent[] = [];

  [...events]
    .sort((a, b) => a.id - b.id)
    .forEach((event) => {
      const previous = grouped.at(-1);
      const isSameRun =
        previous &&
        previous.type === event.type &&
        previous.attempt === event.attempt &&
        previous.worker_id === event.worker_id;

      if (isSameRun) {
        previous.lastId = event.id;
        previous.repeatCount += 1;
        previous.created_at = event.created_at;
        previous.message = event.message;
        previous.data = event.data;
        return;
      }

      grouped.push({ ...event, firstId: event.id, lastId: event.id, repeatCount: 1 });
    });

  return grouped.reverse();
}

export function JobDetailPage() {
  const { jobId } = useParams();
  const [job, setJob] = useState<Job | null>(null);
  const [events, setEvents] = useState<JobEvent[]>([]);

  const refresh = useCallback(async () => {
    if (!jobId) return;
    const [jobData, eventData] = await Promise.all([api.getJob(jobId), api.listJobEvents(jobId)]);
    setJob(jobData);
    setEvents(eventData);
  }, [jobId]);

  useEffect(() => {
    void refresh().catch((caught) => toast.error(caught instanceof Error ? caught.message : String(caught)));
    const id = window.setInterval(() => void refresh().catch(() => undefined), 1000);
    return () => window.clearInterval(id);
  }, [refresh]);

  const timelineEvents = useMemo(() => buildTimeline(events), [events]);

  async function retry() {
    if (!job) return;
    try {
      await api.retryJob(job.id);
      await refresh();
      toast.success("Job returned to the queue.");
    } catch (caught) {
      toast.error(caught instanceof Error ? caught.message : String(caught));
    }
  }

  if (!job) {
    return (
      <div className="page">
        <EmptyState title="Loading job" />
      </div>
    );
  }

  return (
    <div className="page">
      <header className="page-header">
        <div>
          <span className="eyebrow">Job detail</span>
          <h2>
            <code className="inline-code">{job.type}</code>
          </h2>
        </div>
        <div className="row-actions">
          <Link className="secondary-button" to="/jobs">
            Back
          </Link>
          <button type="button" disabled={job.status !== "failed"} onClick={() => void retry()}>
            <RotateCcw size={16} /> Retry
          </button>
        </div>
      </header>

      <section className="stats-grid">
        <div className="stat-card">
          <span>Status</span>
          <StatusBadge status={job.status} />
        </div>
        <div className="stat-card">
          <span>Priority</span>
          <strong>{job.priority}</strong>
        </div>
        <div className="stat-card">
          <span>Attempts</span>
          <strong>
            {job.attempts}/{job.max_attempts}
          </strong>
        </div>
      </section>
      <div className="stat-card">
        <span>Locked by</span>
        <code className="code-token wrap">{job.locked_by ?? "-"}</code>
      </div>

      <section className="detail-grid">
        <section className="panel">
          <div className="section-title">
            <h3>Metadata</h3>
          </div>
          <div className="detail-fields">
            <div className="detail-field">
              <span>ID</span>
              <code className="code-token wrap">{job.id}</code>
            </div>
            <div className="detail-field">
              <span>Available</span>
              <DateTime value={job.available_at} />
            </div>
            <div className="detail-field">
              <span>Locked until</span>
              <DateTime value={job.locked_until} />
            </div>
            <div className="detail-field">
              <span>Finished</span>
              <DateTime value={job.finished_at} />
            </div>
            <div className="detail-field">
              <span>Idempotency</span>
              <code className="code-token wrap">{job.idempotency_key ?? "-"}</code>
            </div>
          </div>
        </section>

        <section className="panel">
          <div className="json-stack">
            <div>
              <div className="section-title">
                <h3>Payload</h3>
              </div>
              <pre className="json-block">{JSON.stringify(job.payload, null, 2)}</pre>
            </div>
            <div>
              <div className="section-title">
                <h3>Result</h3>
              </div>
              <pre className="json-block">{JSON.stringify(job.result ?? null, null, 2)}</pre>
            </div>
            {job.last_error && <p className="error error-block">{job.last_error}</p>}
          </div>
        </section>

        <section className="panel detail-wide">
          <div className="section-title">
            <h3>Event Timeline</h3>
          </div>
          <div className="timeline-list">
            {timelineEvents.map((event) => (
              <article className="timeline-item" key={`${event.firstId}-${event.lastId}`}>
                <span className="timeline-dot" aria-hidden="true" />
                <div className="timeline-card">
                  <div className="timeline-heading">
                    <strong>{eventTitle(event.type)}</strong>
                    {event.repeatCount > 1 && <span className="timeline-count">{event.repeatCount} events</span>}
                  </div>
                  <div className="timeline-meta">
                    <span>{event.worker_id ?? `attempt ${event.attempt}`}</span>
                    <DateTime value={event.created_at} />
                  </div>
                  {event.message && <p>{event.message}</p>}
                </div>
              </article>
            ))}
            {!timelineEvents.length && <EmptyState title="No events for this job" />}
          </div>
        </section>
      </section>
    </div>
  );
}
