import Link from "next/link";
import { useRouter } from "next/router";
import { useCallback, useEffect, useState } from "react";
import Layout from "../../components/Layout";
import {
  humanizeStatus,
  Metric,
  PageState,
  StatusBadge,
} from "../../components/PortalUi";
import JobMap from "../../components/map/JobMap";
import {
  pointSummary,
  type LiveStatus,
  type MapPoint,
} from "../../components/map/types";
import { api } from "../../lib/api";
import { useRequireAuth } from "../../lib/auth-context";
import { useJobStream } from "../../lib/use-job-stream";

interface JobDetail {
  id: string;
  ticketNumber: string;
  title: string;
  description: string | null;
  address: string | null;
  status: string;
  source: string;
  dueAt: string | null;
  createdAt: string;
  assignedTo: { id: string; name: string; email: string } | null;
  _count: { points: number };
}

const STATUSES = ["OPEN", "IN_PROGRESS", "COMPLETED", "CANCELLED"];

export default function JobDetailPage() {
  const { user, activeOrg, loading } = useRequireAuth();
  const router = useRouter();
  const jobId =
    typeof router.query.jobId === "string" ? router.query.jobId : null;
  const orgId = activeOrg?.org.id ?? null;

  const [job, setJob] = useState<JobDetail | null>(null);
  const [points, setPoints] = useState<MapPoint[]>([]);
  const [live, setLive] = useState(0);
  const [liveStatus, setLiveStatus] = useState<LiveStatus | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [fetching, setFetching] = useState(false);
  const [updatingStatus, setUpdatingStatus] = useState(false);

  useEffect(() => {
    if (!orgId || !jobId) {
      return;
    }
    let cancelled = false;
    setJob(null);
    setPoints([]);
    setLive(0);
    setLiveStatus(null);
    setError(null);
    setFetching(true);
    Promise.all([
      api.get<JobDetail>(`/api/orgs/${orgId}/jobs/${jobId}`),
      api.get<{ points: MapPoint[] }>(
        `/api/orgs/${orgId}/jobs/${jobId}/points`,
      ),
    ])
      .then(([jobResult, pointResult]) => {
        if (cancelled) return;
        setJob(jobResult);
        setPoints(pointResult.points);
      })
      .catch((err) => {
        if (!cancelled) setError(err.message);
      })
      .finally(() => {
        if (!cancelled) setFetching(false);
      });
    return () => {
      cancelled = true;
    };
  }, [orgId, jobId]);

  const onLivePoints = useCallback((incoming: MapPoint[]) => {
    setPoints((prev) => {
      const seen = new Set(prev.map((p) => p.id));
      const fresh = incoming.filter((p) => !seen.has(p.id));
      return fresh.length > 0 ? [...prev, ...fresh] : prev;
    });
    setLive((n) => n + incoming.length);
  }, []);

  const onStatus = useCallback(
    (status: LiveStatus) => setLiveStatus(status),
    [],
  );

  const streamState = useJobStream(jobId, onLivePoints, onStatus);

  const updateStatus = async (status: string) => {
    if (!orgId || !jobId) {
      return;
    }
    setUpdatingStatus(true);
    try {
      setJob(
        await api.patch<JobDetail>(`/api/orgs/${orgId}/jobs/${jobId}`, {
          status,
        }),
      );
      setError(null);
    } catch (err: any) {
      setError(err.message);
    } finally {
      setUpdatingStatus(false);
    }
  };

  if (loading || !user) {
    return <PageState kind="loading" title="Loading your workspace…" />;
  }

  const streamStatus = streamState.toUpperCase();
  const streamLabel =
    streamState === "live"
      ? live > 0
        ? `Live · ${live} new ${live === 1 ? "point" : "points"} this session`
        : "Live · waiting for activity"
      : undefined;

  return (
    <Layout title={job ? job.ticketNumber : "Job"}>
      <nav className="ul-breadcrumb" aria-label="Breadcrumb">
        <Link href="/">← All jobs</Link>
      </nav>

      {error && !job ? (
        <PageState kind="error" title="Job could not be loaded">
          {error}
        </PageState>
      ) : fetching || !job ? (
        <PageState kind="loading" title="Loading job and locate points…" />
      ) : (
        <>
          <header className="ul-detail-header">
            <div>
              <span className="ul-detail-header__eyebrow">Locate job</span>
              <div className="ul-detail-header__title-row">
                <h1>{job.ticketNumber}</h1>
                <span className="ul-detail-header__title">{job.title}</span>
              </div>
              <p className="ul-detail-header__subtitle">
                {job.address ?? "No address"} · {humanizeStatus(job.source)}{" "}
                source
              </p>
            </div>
            <label className="ul-field">
              <span className="ul-field__label">Job status</span>
              <select
                value={job.status}
                disabled={updatingStatus}
                aria-describedby="job-status-update"
                onChange={(event) => updateStatus(event.target.value)}
              >
                {STATUSES.map((status) => (
                  <option key={status} value={status}>
                    {humanizeStatus(status)}
                  </option>
                ))}
              </select>
              <span
                id="job-status-update"
                className="ul-visually-hidden"
                aria-live="polite"
              >
                {updatingStatus
                  ? "Updating job status"
                  : `Current status: ${humanizeStatus(job.status)}`}
              </span>
            </label>
          </header>

          {error && (
            <PageState kind="error" title="The latest update failed">
              {error}
            </PageState>
          )}

          <section className="ul-panel ul-job-summary" aria-label="Job summary">
            <Metric
              label="Status"
              value={<StatusBadge status={job.status} />}
            />
            <Metric
              label="Created"
              value={new Date(job.createdAt).toLocaleDateString()}
              detail={new Date(job.createdAt).toLocaleTimeString()}
            />
            <Metric
              label="Locate by"
              value={
                job.dueAt ? new Date(job.dueAt).toLocaleDateString() : "Not set"
              }
              detail={
                job.dueAt ? new Date(job.dueAt).toLocaleTimeString() : undefined
              }
            />
            <Metric
              label="Assigned to"
              value={job.assignedTo?.name ?? "Unassigned"}
              detail={job.assignedTo?.email}
            />
            <Metric label="Source" value={humanizeStatus(job.source)} />
            <Metric label="Recorded points" value={points.length} />
            {job.description && (
              <p className="ul-job-summary__description">{job.description}</p>
            )}
          </section>

          <div className="ul-live-strip" aria-live="polite">
            <StatusBadge status={streamStatus} label={streamLabel} />
            {points.length > 0 && (
              <span className="ul-live-strip__latest">
                Latest point: {pointSummary(points[points.length - 1])}
              </span>
            )}
            {liveStatus && (
              <StatusBadge
                status="LIVE"
                label={`Transmitter ${liveStatus.serial} · ${new Date(liveStatus.recordedAt).toLocaleTimeString()}`}
              />
            )}
          </div>

          <section
            className="ul-map-section"
            aria-labelledby="live-map-heading"
          >
            <div className="ul-section-heading">
              <div>
                <span className="ul-section-heading__eyebrow">
                  Live operations
                </span>
                <h2 id="live-map-heading">Locate map</h2>
              </div>
              <StatusBadge status={streamStatus} />
            </div>
            <JobMap points={points} liveStatus={liveStatus} heightPx={520} />
          </section>
        </>
      )}
    </Layout>
  );
}
