﻿/**
 * Orchestrator layout with a split list/detail experience.
 */

import React, { useCallback, useEffect, useMemo, useState } from "react";
import {
  ArrowUpDown,
  Calendar,
  CheckCircle2,
  ChevronDown,
  Clock,
  Copy,
  DollarSign,
  ExternalLink,
  FileText,
  Filter,
  GraduationCap,
  Loader2,
  MapPin,
  MoreHorizontal,
  Play,
  RefreshCcw,
  Search,
  Settings,
  Sparkles,
  XCircle,
} from "lucide-react";
import { Link } from "react-router-dom";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import { toast } from "sonner";

import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
  DropdownMenu,
  DropdownMenuCheckboxItem,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuRadioGroup,
  DropdownMenuRadioItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Input } from "@/components/ui/input";
import { Separator } from "@/components/ui/separator";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Textarea } from "@/components/ui/textarea";
import { cn } from "@/lib/utils";
import { copyTextToClipboard, formatJobForWebhook } from "@client/lib/jobCopy";
import { PipelineProgress } from "../components";
import * as api from "../api";
import { TailoringEditor } from "../components/TailoringEditor";
import type { Job, JobSource, JobStatus } from "../../shared/types";

const DEFAULT_PIPELINE_SOURCES: JobSource[] = ["gradcracker", "indeed", "linkedin", "ukvisajobs"];
const PIPELINE_SOURCES_STORAGE_KEY = "jobops.pipeline.sources";

const sourceLabel: Record<JobSource, string> = {
  gradcracker: "Gradcracker",
  indeed: "Indeed",
  linkedin: "LinkedIn",
  ukvisajobs: "UK Visa Jobs",
};

const orderedSources: JobSource[] = ["gradcracker", "indeed", "linkedin", "ukvisajobs"];

const statusTokens: Record<
  JobStatus,
  { label: string; badge: string; dot: string }
> = {
  discovered: {
    label: "Discovered",
    badge: "border-sky-500/30 bg-sky-500/10 text-sky-200",
    dot: "bg-sky-400",
  },
  processing: {
    label: "Processing",
    badge: "border-amber-500/30 bg-amber-500/10 text-amber-200",
    dot: "bg-amber-400",
  },
  ready: {
    label: "Ready",
    badge: "border-emerald-500/30 bg-emerald-500/10 text-emerald-200",
    dot: "bg-emerald-400",
  },
  applied: {
    label: "Applied",
    badge: "border-emerald-500/30 bg-emerald-500/10 text-emerald-200",
    dot: "bg-emerald-400",
  },
  rejected: {
    label: "Rejected",
    badge: "border-rose-500/30 bg-rose-500/10 text-rose-200",
    dot: "bg-rose-400",
  },
  expired: {
    label: "Expired",
    badge: "border-muted-foreground/20 bg-muted/30 text-muted-foreground",
    dot: "bg-muted-foreground",
  },
};

type FilterTab = "ready" | "discovered" | "applied" | "all";

type SortKey = "discoveredAt" | "score" | "title" | "employer";
type SortDirection = "asc" | "desc";

interface JobSort {
  key: SortKey;
  direction: SortDirection;
}

const DEFAULT_SORT: JobSort = { key: "score", direction: "desc" };

const sortLabels: Record<JobSort["key"], string> = {
  discoveredAt: "Discovered",
  score: "Score",
  title: "Title",
  employer: "Company",
};

const defaultSortDirection: Record<JobSort["key"], SortDirection> = {
  discoveredAt: "desc",
  score: "desc",
  title: "asc",
  employer: "asc",
};

const tabs: Array<{ id: FilterTab; label: string; statuses: JobStatus[] }> = [
  { id: "ready", label: "Ready", statuses: ["ready"] },
  { id: "discovered", label: "Discovered", statuses: ["discovered", "processing"] },
  { id: "applied", label: "Applied", statuses: ["applied"] },
  { id: "all", label: "All Jobs", statuses: [] },
];

const emptyStateCopy: Record<FilterTab, string> = {
  ready: "Run the pipeline to discover and process new jobs.",
  discovered: "All discovered jobs have been processed.",
  applied: "You have not applied to any jobs yet.",
  all: "No jobs in the system yet. Run the pipeline to get started.",
};

const formatDate = (dateStr: string | null) => {
  if (!dateStr) return null;
  try {
    return new Date(dateStr).toLocaleDateString("en-GB", {
      day: "numeric",
      month: "short",
      year: "numeric",
    });
  } catch {
    return dateStr;
  }
};

const formatDateTime = (dateStr: string | null) => {
  if (!dateStr) return null;
  try {
    const normalized = dateStr.includes("T") ? dateStr : dateStr.replace(" ", "T");
    const parsed = new Date(normalized);
    if (Number.isNaN(parsed.getTime())) return dateStr;
    const date = parsed.toLocaleDateString("en-GB", {
      day: "numeric",
      month: "short",
      year: "numeric",
    });
    const time = parsed.toLocaleTimeString("en-GB", {
      hour: "2-digit",
      minute: "2-digit",
    });
    return `${date} ${time}`;
  } catch {
    return dateStr;
  }
};

const dateValue = (value: string | null) => {
  if (!value) return null;
  const parsed = Date.parse(value);
  return Number.isFinite(parsed) ? parsed : null;
};

const compareString = (a: string, b: string) => a.localeCompare(b, undefined, { sensitivity: "base" });
const compareNumber = (a: number, b: number) => a - b;

const compareJobs = (a: Job, b: Job, sort: JobSort) => {
  let value = 0;

  switch (sort.key) {
    case "title":
      value = compareString(a.title, b.title);
      break;
    case "employer":
      value = compareString(a.employer, b.employer);
      break;
    case "score": {
      const aScore = a.suitabilityScore;
      const bScore = b.suitabilityScore;

      if (aScore == null && bScore == null) {
        value = 0;
        break;
      }
      if (aScore == null) return 1;
      if (bScore == null) return -1;
      value = compareNumber(aScore, bScore);
      break;
    }
    case "discoveredAt":
      const aDate = dateValue(a.discoveredAt);
      const bDate = dateValue(b.discoveredAt);
      if (aDate == null && bDate == null) {
        value = 0;
        break;
      }
      if (aDate == null) return 1;
      if (bDate == null) return -1;
      value = compareNumber(aDate, bDate);
      break;
    default:
      value = 0;
  }

  if (value !== 0) return sort.direction === "asc" ? value : -value;
  return a.id.localeCompare(b.id);
};

const jobMatchesQuery = (job: Job, query: string) => {
  const normalized = query.trim().toLowerCase();
  if (!normalized) return true;
  const haystack = [
    job.title,
    job.employer,
    job.location,
    job.source,
    job.status,
    job.jobType,
    job.jobFunction,
  ]
    .filter(Boolean)
    .join(" ")
    .toLowerCase();
  return haystack.includes(normalized);
};

const stripHtml = (value: string) => value.replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim();

const StatusPill: React.FC<{ status: JobStatus }> = ({ status }) => {
  const tokens = statusTokens[status];
  return (
    <span
      className={cn(
        "inline-flex items-center gap-2 rounded-full border px-2.5 py-1 text-[11px] font-semibold uppercase tracking-wide",
        tokens.badge,
      )}
    >
      <span className={cn("h-1.5 w-1.5 rounded-full", tokens.dot)} />
      {tokens.label}
    </span>
  );
};

const ScoreMeter: React.FC<{ score: number | null }> = ({ score }) => {
  if (score == null) {
    return <span className="text-xs text-muted-foreground">Not scored</span>;
  }

  return (
    <div className="flex items-center gap-2 text-xs text-muted-foreground">
      <div className="h-1.5 w-16 rounded-full bg-muted/40">
        <div
          className="h-1.5 rounded-full bg-primary/80"
          style={{ width: `${Math.max(4, Math.min(100, score))}%` }}
        />
      </div>
      <span className="tabular-nums">{score}</span>
    </div>
  );
};

export const OrchestratorPage: React.FC = () => {
  const [jobs, setJobs] = useState<Job[]>([]);
  const [stats, setStats] = useState<Record<JobStatus, number>>({
    discovered: 0,
    processing: 0,
    ready: 0,
    applied: 0,
    rejected: 0,
    expired: 0,
  });
  const [isLoading, setIsLoading] = useState(true);
  const [isPipelineRunning, setIsPipelineRunning] = useState(false);
  const [processingJobId, setProcessingJobId] = useState<string | null>(null);
  const [activeTab, setActiveTab] = useState<FilterTab>("ready");
  const [searchQuery, setSearchQuery] = useState("");
  const [sourceFilter, setSourceFilter] = useState<JobSource | "all">("all");
  const [sort, setSort] = useState<JobSort>(DEFAULT_SORT);
  const [selectedJobId, setSelectedJobId] = useState<string | null>(null);
  const [detailTab, setDetailTab] = useState<"overview" | "tailoring" | "description">("overview");
  const [isEditingDescription, setIsEditingDescription] = useState(false);
  const [editedDescription, setEditedDescription] = useState("");
  const [isSavingDescription, setIsSavingDescription] = useState(false);
  const [pipelineSources, setPipelineSources] = useState<JobSource[]>(() => {
    try {
      const raw = localStorage.getItem(PIPELINE_SOURCES_STORAGE_KEY);
      if (!raw) return DEFAULT_PIPELINE_SOURCES;
      const parsed = JSON.parse(raw) as unknown;
      if (!Array.isArray(parsed)) return DEFAULT_PIPELINE_SOURCES;
      const next = parsed.filter((value): value is JobSource => orderedSources.includes(value as JobSource));
      return next.length > 0 ? next : DEFAULT_PIPELINE_SOURCES;
    } catch {
      return DEFAULT_PIPELINE_SOURCES;
    }
  });

  useEffect(() => {
    try {
      localStorage.setItem(PIPELINE_SOURCES_STORAGE_KEY, JSON.stringify(pipelineSources));
    } catch {
      // Ignore localStorage errors
    }
  }, [pipelineSources]);

  const loadJobs = useCallback(async () => {
    try {
      setIsLoading(true);
      const data = await api.getJobs();
      setJobs(data.jobs);
      setStats(data.byStatus);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to load jobs";
      toast.error(message);
    } finally {
      setIsLoading(false);
    }
  }, []);

  const checkPipelineStatus = useCallback(async () => {
    try {
      const status = await api.getPipelineStatus();
      setIsPipelineRunning(status.isRunning);
    } catch {
      // Ignore errors
    }
  }, []);

  useEffect(() => {
    loadJobs();
    checkPipelineStatus();

    const interval = setInterval(() => {
      loadJobs();
      checkPipelineStatus();
    }, 10000);

    return () => clearInterval(interval);
  }, [loadJobs, checkPipelineStatus]);

  const handleRunPipeline = async () => {
    try {
      setIsPipelineRunning(true);
      await api.runPipeline({ sources: pipelineSources });
      toast.message("Pipeline started", {
        description: `Sources: ${pipelineSources.join(", ")}. This may take a few minutes.`,
      });

      const pollInterval = setInterval(async () => {
        try {
          const status = await api.getPipelineStatus();
          if (!status.isRunning) {
            clearInterval(pollInterval);
            setIsPipelineRunning(false);
            await loadJobs();
            toast.success("Pipeline completed");
          }
        } catch {
          // Ignore errors
        }
      }, 5000);
    } catch (error) {
      setIsPipelineRunning(false);
      const message = error instanceof Error ? error.message : "Failed to start pipeline";
      toast.error(message);
    }
  };

  const handleProcess = async (jobId: string) => {
    try {
      setProcessingJobId(jobId);
      const job = jobs.find((item) => item.id === jobId);
      const force = job?.status === "ready";
      await api.processJob(jobId, { force });
      toast.success(force ? "Resume regenerated successfully" : "Resume generated successfully");
      await loadJobs();
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to process job";
      toast.error(message);
    } finally {
      setProcessingJobId(null);
    }
  };

  const handleApply = async (jobId: string) => {
    try {
      await api.markAsApplied(jobId);
      toast.success("Marked as applied");
      await loadJobs();
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to mark as applied";
      toast.error(message);
    }
  };

  const handleReject = async (jobId: string) => {
    try {
      await api.rejectJob(jobId);
      toast.message("Job skipped");
      await loadJobs();
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to reject job";
      toast.error(message);
    }
  };

  const handleCopyInfo = async (job: Job) => {
    try {
      await copyTextToClipboard(formatJobForWebhook(job));
      toast.success("Copied job info", { description: "Webhook payload copied to clipboard." });
    } catch {
      toast.error("Could not copy job info");
    }
  };

  const activeJobs = useMemo(() => {
    let filtered = jobs;

    if (activeTab === "ready") {
      filtered = filtered.filter((job) => job.status === "ready");
    } else if (activeTab === "discovered") {
      filtered = filtered.filter((job) => job.status === "discovered" || job.status === "processing");
    } else if (activeTab === "applied") {
      filtered = filtered.filter((job) => job.status === "applied");
    }

    if (sourceFilter !== "all") {
      filtered = filtered.filter((job) => job.source === sourceFilter);
    }

    if (searchQuery.trim()) {
      filtered = filtered.filter((job) => jobMatchesQuery(job, searchQuery));
    }

    return [...filtered].sort((a, b) => compareJobs(a, b, sort));
  }, [jobs, activeTab, sourceFilter, searchQuery, sort]);

  useEffect(() => {
    if (activeJobs.length === 0) {
      setSelectedJobId(null);
      return;
    }
    if (!selectedJobId || !activeJobs.some((job) => job.id === selectedJobId)) {
      setSelectedJobId(activeJobs[0].id);
    }
  }, [activeJobs, selectedJobId]);

  const selectedJob = useMemo(
    () => (selectedJobId ? jobs.find((job) => job.id === selectedJobId) ?? null : null),
    [jobs, selectedJobId],
  );

  const description = useMemo(() => {
    if (!selectedJob?.jobDescription) return "No description available.";
    const jd = selectedJob.jobDescription;
    if (jd.includes("<") && jd.includes(">")) return stripHtml(jd);
    return jd;
  }, [selectedJob]);

  useEffect(() => {
    if (!selectedJob) {
      setIsEditingDescription(false);
      setEditedDescription("");
      return;
    }
    setIsEditingDescription(false);
    setEditedDescription(selectedJob.jobDescription || "");
  }, [selectedJob?.id]);

  useEffect(() => {
    if (!selectedJob) return;
    if (!isEditingDescription) {
      setEditedDescription(selectedJob.jobDescription || "");
    }
  }, [selectedJob?.jobDescription, isEditingDescription]);

  const handleSaveDescription = async () => {
    if (!selectedJob) return;
    try {
      setIsSavingDescription(true);
      await api.updateJob(selectedJob.id, { jobDescription: editedDescription });
      toast.success("Job description updated");
      setIsEditingDescription(false);
      await loadJobs();
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to update description";
      toast.error(message);
    } finally {
      setIsSavingDescription(false);
    }
  };

  const totalJobs = Object.values(stats).reduce((a, b) => a + b, 0);
  const activeResultsCount = activeJobs.length;
  const selectedHasPdf = !!selectedJob?.pdfPath;
  const selectedJobLink = selectedJob ? selectedJob.applicationLink || selectedJob.jobUrl : "#";
  const selectedPdfHref = selectedJob ? `/pdfs/resume_${selectedJob.id}.pdf` : "#";
  const selectedDeadline = selectedJob ? formatDate(selectedJob.deadline) : null;
  const selectedDiscoveredAt = selectedJob ? formatDateTime(selectedJob.discoveredAt) : null;
  const canApply = selectedJob?.status === "ready";
  const canProcess = selectedJob ? ["discovered", "ready"].includes(selectedJob.status) : false;
  const canReject = selectedJob ? ["discovered", "ready"].includes(selectedJob.status) : false;
  const showReadyPdf = activeTab === "ready";
  const showGeneratePdf = activeTab === "discovered";
  const isProcessingSelected =
    selectedJob ? processingJobId === selectedJob.id || selectedJob.status === "processing" : false;

  const toggleSource = (source: JobSource, checked: boolean) => {
    const next = checked
      ? Array.from(new Set([...pipelineSources, source]))
      : pipelineSources.filter((s) => s !== source);

    if (next.length === 0) return;
    setPipelineSources(next);
  };

  const counts = useMemo(() => {
    const byTab: Record<FilterTab, number> = {
      ready: 0,
      discovered: 0,
      applied: 0,
      all: jobs.length,
    };

    for (const job of jobs) {
      if (job.status === "ready") byTab.ready += 1;
      if (job.status === "applied") byTab.applied += 1;
      if (job.status === "discovered" || job.status === "processing") byTab.discovered += 1;
    }

    return byTab;
  }, [jobs]);

  return (
    <>
      <header className="sticky top-0 z-40 border-b bg-background/80 backdrop-blur supports-[backdrop-filter]:bg-background/60">
        <div className="container mx-auto flex max-w-7xl items-center justify-between gap-4 px-4 py-4">
          <div className="flex items-center gap-3">
            <div className="flex h-9 w-9 items-center justify-center rounded-lg border border-border/60 bg-muted/30">
              <Sparkles className="h-4 w-4 text-muted-foreground" />
            </div>
            <div className="leading-tight">
              <div className="text-sm font-semibold tracking-tight">Job Ops</div>
              <div className="text-xs text-muted-foreground">Orchestrator</div>
            </div>
            {isPipelineRunning && (
              <span className="inline-flex items-center gap-2 rounded-full border border-amber-500/30 bg-amber-500/10 px-2 py-1 text-[11px] font-semibold uppercase tracking-wide text-amber-200">
                <span className="h-1.5 w-1.5 rounded-full bg-amber-400 animate-pulse" />
                Pipeline running
              </span>
            )}
          </div>

          <div className="flex items-center gap-2">
            <Button variant="ghost" size="icon" onClick={loadJobs} disabled={isLoading} aria-label="Refresh jobs">
              <RefreshCcw className="h-4 w-4" />
            </Button>
            <Button asChild variant="ghost" size="icon" aria-label="Settings">
              <Link to="/settings">
                <Settings className="h-4 w-4" />
              </Link>
            </Button>

            <div className="flex items-center gap-1">
              <Button size="sm" onClick={handleRunPipeline} disabled={isPipelineRunning} className="gap-2">
                {isPipelineRunning ? <Loader2 className="h-4 w-4 animate-spin" /> : <Play className="h-4 w-4" />}
                {isPipelineRunning ? "Running" : "Run pipeline"}
              </Button>

              <DropdownMenu>
                <DropdownMenuTrigger asChild>
                  <Button size="icon" variant="outline" disabled={isPipelineRunning} aria-label="Select pipeline sources">
                    <ChevronDown className="h-4 w-4" />
                  </Button>
                </DropdownMenuTrigger>
                <DropdownMenuContent align="end" className="w-56">
                  <DropdownMenuLabel>Sources</DropdownMenuLabel>
                  <DropdownMenuSeparator />
                  {orderedSources.map((source) => (
                    <DropdownMenuCheckboxItem
                      key={source}
                      checked={pipelineSources.includes(source)}
                      onCheckedChange={(checked) => toggleSource(source, Boolean(checked))}
                    >
                      {sourceLabel[source]}
                    </DropdownMenuCheckboxItem>
                  ))}
                  <DropdownMenuSeparator />
                  <DropdownMenuItem onSelect={() => setPipelineSources(orderedSources)}>All sources</DropdownMenuItem>
                  <DropdownMenuItem onSelect={() => setPipelineSources(["gradcracker"])}>Gradcracker only</DropdownMenuItem>
                  <DropdownMenuItem onSelect={() => setPipelineSources(["indeed", "linkedin"])}>
                    Indeed + LinkedIn only
                  </DropdownMenuItem>
                </DropdownMenuContent>
              </DropdownMenu>
            </div>
          </div>
        </div>
      </header>

      <main className="container mx-auto max-w-7xl space-y-6 px-4 py-6 pb-12">
        <section className="space-y-3">
          <div className="flex items-center justify-between">
            <div className="space-y-1">
              <h1 className="text-xl font-semibold tracking-tight">Pipeline console</h1>
              <p className="text-sm text-muted-foreground">
                Focused workspace with a split list/detail layout and icon-led actions.
              </p>
            </div>
            <div className="text-sm text-muted-foreground">{totalJobs} total jobs</div>
          </div>

          {isPipelineRunning && (
            <div className="max-w-3xl">
              <PipelineProgress isRunning={isPipelineRunning} />
            </div>
          )}

          <div className="grid overflow-hidden rounded-xl border border-border/60 bg-card/40 sm:grid-cols-3 lg:grid-cols-6">
            {[
              { label: "Discovered", value: stats.discovered },
              { label: "Processing", value: stats.processing },
              { label: "Ready", value: stats.ready },
              { label: "Applied", value: stats.applied },
              { label: "Rejected", value: stats.rejected },
              { label: "Expired", value: stats.expired },
            ].map((item, index) => (
              <div
                key={item.label}
                className={cn(
                  "flex flex-col justify-between gap-1 px-4 py-3",
                  index > 0 && "border-t border-border/60 sm:border-t-0 sm:border-l",
                  index > 0 && index % 3 === 0 && "sm:border-l-0 sm:border-t",
                  index > 2 && "lg:border-t-0 lg:border-l",
                )}
              >
                <span className="text-xs text-muted-foreground">{item.label}</span>
                <span className="text-lg font-semibold tabular-nums">{item.value}</span>
              </div>
            ))}
          </div>
        </section>
        <section className="space-y-3">
          <Tabs value={activeTab} onValueChange={(value) => setActiveTab(value as FilterTab)}>
            <div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
              <TabsList className="h-9 w-full lg:w-auto">
                {tabs.map((tab) => (
                  <TabsTrigger key={tab.id} value={tab.id} className="flex-1 lg:flex-none">
                    {tab.label}
                    <span className="ml-2 text-xs tabular-nums text-muted-foreground">({counts[tab.id]})</span>
                  </TabsTrigger>
                ))}
              </TabsList>

              <div className="flex flex-wrap items-center gap-2">
                <div className="relative w-full min-w-[220px] flex-1 lg:flex-none">
                  <Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
                  <Input
                    value={searchQuery}
                    onChange={(event) => setSearchQuery(event.target.value)}
                    placeholder="Filter jobs..."
                    className="pl-9"
                  />
                </div>

                <DropdownMenu>
                  <DropdownMenuTrigger asChild>
                    <Button variant="outline" size="sm" className="h-9 gap-2">
                      <Filter className="h-4 w-4" />
                      Source: {sourceFilter === "all" ? "All" : sourceLabel[sourceFilter]}
                    </Button>
                  </DropdownMenuTrigger>
                  <DropdownMenuContent align="end" className="w-56">
                    <DropdownMenuLabel>Filter by source</DropdownMenuLabel>
                    <DropdownMenuSeparator />
                    <DropdownMenuRadioGroup
                      value={sourceFilter}
                      onValueChange={(value) => setSourceFilter(value as JobSource | "all")}
                    >
                      <DropdownMenuRadioItem value="all">All Sources</DropdownMenuRadioItem>
                      {(Object.keys(sourceLabel) as JobSource[]).map((key) => (
                        <DropdownMenuRadioItem key={key} value={key}>
                          {sourceLabel[key]}
                        </DropdownMenuRadioItem>
                      ))}
                    </DropdownMenuRadioGroup>
                  </DropdownMenuContent>
                </DropdownMenu>

                <DropdownMenu>
                  <DropdownMenuTrigger asChild>
                    <Button variant="outline" size="sm" className="h-9 gap-2">
                      <ArrowUpDown className="h-4 w-4" />
                      Sort: {sortLabels[sort.key]}
                    </Button>
                  </DropdownMenuTrigger>
                  <DropdownMenuContent align="end" className="w-56">
                    <DropdownMenuLabel>Sort by</DropdownMenuLabel>
                    <DropdownMenuSeparator />
                    <DropdownMenuRadioGroup
                      value={sort.key}
                      onValueChange={(value) =>
                        setSort({
                          key: value as JobSort["key"],
                          direction: defaultSortDirection[value as JobSort["key"]],
                        })
                      }
                    >
                      {(Object.keys(sortLabels) as Array<JobSort["key"]>).map((key) => (
                        <DropdownMenuRadioItem key={key} value={key}>
                          {sortLabels[key]}
                        </DropdownMenuRadioItem>
                      ))}
                    </DropdownMenuRadioGroup>
                    <DropdownMenuSeparator />
                    <DropdownMenuItem
                      onSelect={() =>
                        setSort((current) => ({
                          ...current,
                          direction: current.direction === "asc" ? "desc" : "asc",
                        }))
                      }
                    >
                      Direction: {sort.direction === "asc" ? "Ascending" : "Descending"}
                    </DropdownMenuItem>
                  </DropdownMenuContent>
                </DropdownMenu>

                <Badge variant="outline" className="h-9 px-3 text-xs tabular-nums text-muted-foreground">
                  {activeResultsCount} jobs
                </Badge>
              </div>
            </div>
          </Tabs>
        </section>
        <section className="grid gap-4 lg:grid-cols-[minmax(0,1fr)_minmax(0,420px)]">
          <div className="rounded-xl border border-border/60 bg-card/40">
            {activeJobs.length === 0 ? (
              <div className="flex flex-col items-center justify-center gap-2 px-6 py-12 text-center">
                <div className="text-base font-semibold">No jobs found</div>
                <p className="max-w-md text-sm text-muted-foreground">
                  {searchQuery.trim() ? `No jobs match "${searchQuery.trim()}".` : emptyStateCopy[activeTab]}
                </p>
              </div>
            ) : (
              <div className="divide-y divide-border/60">
                {activeJobs.map((job) => {
                  const isSelected = job.id === selectedJobId;
                  return (
                    <button
                      key={job.id}
                      type="button"
                      onClick={() => setSelectedJobId(job.id)}
                      className={cn(
                        "flex w-full items-start gap-4 px-4 py-3 text-left transition-colors",
                        isSelected ? "bg-muted/40" : "hover:bg-muted/30",
                      )}
                      aria-pressed={isSelected}
                    >
                      <span className={cn("mt-1 h-2.5 w-2.5 rounded-full", statusTokens[job.status].dot)} />
                      <div className="min-w-0 flex-1 space-y-1">
                        <div className="truncate text-sm font-semibold">{job.title}</div>
                        <div className="text-xs text-muted-foreground">{job.employer}</div>
                        <div className="flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
                          {job.location && (
                            <span className="flex items-center gap-1">
                              <MapPin className="h-3.5 w-3.5" />
                              {job.location}
                            </span>
                          )}
                          {job.deadline && (
                            <span className="flex items-center gap-1">
                              <Calendar className="h-3.5 w-3.5" />
                              {formatDate(job.deadline)}
                            </span>
                          )}
                          {job.discoveredAt && (
                            <span className="flex items-center gap-1">
                              <Clock className="h-3.5 w-3.5" />
                              Discovered {formatDateTime(job.discoveredAt)}
                            </span>
                          )}
                        </div>
                      </div>
                      <div className="flex flex-col items-end gap-2">
                        <ScoreMeter score={job.suitabilityScore} />
                        <span className="text-[11px] font-semibold uppercase tracking-wide text-muted-foreground">
                          {statusTokens[job.status].label}
                        </span>
                      </div>
                    </button>
                  );
                })}
              </div>
            )}
          </div>

          <div className="rounded-xl border border-border/60 bg-card/40 p-4 lg:sticky lg:top-24 lg:self-start">
            {!selectedJob ? (
              <div className="flex h-full flex-col items-center justify-center gap-2 text-center">
                <div className="text-base font-semibold">Select a job</div>
                <p className="text-sm text-muted-foreground">Pick a job from the list to see details here.</p>
              </div>
            ) : (
              <div className="space-y-4">
                <div className="flex flex-wrap items-start justify-between gap-3">
                  <div className="min-w-0">
                    <div className="truncate text-base font-semibold">{selectedJob.title}</div>
                    <div className="text-sm text-muted-foreground">{selectedJob.employer}</div>
                  </div>
                  <div className="flex flex-wrap items-center gap-2">
                    <Badge variant="outline" className="uppercase tracking-wide">
                      {sourceLabel[selectedJob.source]}
                    </Badge>
                    <StatusPill status={selectedJob.status} />
                  </div>
                </div>

                <div className="flex flex-wrap items-center gap-3 text-xs text-muted-foreground">
                  {selectedJob.location && (
                    <span className="flex items-center gap-1">
                      <MapPin className="h-3.5 w-3.5" />
                      {selectedJob.location}
                    </span>
                  )}
                  {selectedDeadline && (
                    <span className="flex items-center gap-1">
                      <Calendar className="h-3.5 w-3.5" />
                      {selectedDeadline}
                    </span>
                  )}
                  {selectedDiscoveredAt && (
                    <span className="flex items-center gap-1">
                      <Clock className="h-3.5 w-3.5" />
                      Discovered {selectedDiscoveredAt}
                    </span>
                  )}
                  {selectedJob.salary && (
                    <span className="flex items-center gap-1">
                      <DollarSign className="h-3.5 w-3.5" />
                      {selectedJob.salary}
                    </span>
                  )}
                  {selectedJob.degreeRequired && (
                    <span className="flex items-center gap-1">
                      <GraduationCap className="h-3.5 w-3.5" />
                      {selectedJob.degreeRequired}
                    </span>
                  )}
                </div>

                <div className="flex items-center gap-2 text-sm text-muted-foreground">
                  <span>Suitability</span>
                  <ScoreMeter score={selectedJob.suitabilityScore} />
                </div>

                <Separator />

                <div className="flex flex-wrap items-center gap-2">
                  <Button asChild size="sm" variant="outline" className="gap-2">
                    <a href={selectedJobLink} target="_blank" rel="noopener noreferrer">
                      <ExternalLink className="h-4 w-4" />
                      View job
                    </a>
                  </Button>

                  {showReadyPdf &&
                    (selectedHasPdf ? (
                      <Button asChild size="sm" variant="outline" className="gap-2">
                        <a href={selectedPdfHref} target="_blank" rel="noopener noreferrer">
                          <FileText className="h-4 w-4" />
                          View PDF
                        </a>
                      </Button>
                    ) : (
                      <Button size="sm" variant="outline" className="gap-2" disabled>
                        <FileText className="h-4 w-4" />
                        View PDF
                      </Button>
                    ))}

                  {showGeneratePdf && (
                    <Button
                      size="sm"
                      variant="secondary"
                      className="gap-2"
                      onClick={() => handleProcess(selectedJob.id)}
                      disabled={!canProcess || isProcessingSelected}
                    >
                      {isProcessingSelected ? (
                        <Loader2 className="h-4 w-4 animate-spin" />
                      ) : (
                        <RefreshCcw className="h-4 w-4" />
                      )}
                      {isProcessingSelected ? "Generating..." : "Generate PDF"}
                    </Button>
                  )}

                  {canApply && (
                    <Button
                      size="sm"
                      className="gap-2 bg-emerald-500/15 text-emerald-200 hover:bg-emerald-500/25"
                      onClick={() => handleApply(selectedJob.id)}
                    >
                      <CheckCircle2 className="h-4 w-4" />
                      Mark applied
                    </Button>
                  )}

                  <DropdownMenu>
                    <DropdownMenuTrigger asChild>
                      <Button size="icon" variant="ghost" aria-label="More actions">
                        <MoreHorizontal className="h-4 w-4" />
                      </Button>
                    </DropdownMenuTrigger>
                    <DropdownMenuContent align="end">
                      {canProcess && !showGeneratePdf && (
                        <DropdownMenuItem
                          onSelect={() => handleProcess(selectedJob.id)}
                          disabled={isProcessingSelected}
                        >
                          <RefreshCcw className="mr-2 h-4 w-4" />
                          {isProcessingSelected
                            ? "Processing..."
                            : selectedJob.status === "ready"
                              ? "Regenerate PDF"
                              : "Generate PDF"}
                        </DropdownMenuItem>
                      )}
                      <DropdownMenuItem onSelect={() => void handleCopyInfo(selectedJob)}>
                        <Copy className="mr-2 h-4 w-4" />
                        Copy info
                      </DropdownMenuItem>
                      {selectedHasPdf && (
                        <>
                          {!showReadyPdf && (
                            <DropdownMenuItem asChild>
                              <a href={selectedPdfHref} target="_blank" rel="noopener noreferrer">
                                <ExternalLink className="mr-2 h-4 w-4" />
                                View PDF
                              </a>
                            </DropdownMenuItem>
                          )}
                          <DropdownMenuItem asChild>
                            <a href={selectedPdfHref} download={`resume_${selectedJob.id}.pdf`}>
                              <FileText className="mr-2 h-4 w-4" />
                              Download PDF
                            </a>
                          </DropdownMenuItem>
                        </>
                      )}
                      {canReject && (
                        <>
                          <DropdownMenuSeparator />
                          <DropdownMenuItem
                            onSelect={() => handleReject(selectedJob.id)}
                            className="text-destructive focus:text-destructive"
                          >
                            <XCircle className="mr-2 h-4 w-4" />
                            Skip job
                          </DropdownMenuItem>
                        </>
                      )}
                    </DropdownMenuContent>
                  </DropdownMenu>
                </div>
                <Tabs value={detailTab} onValueChange={(value) => setDetailTab(value as typeof detailTab)}>
                  <TabsList className="h-9">
                    <TabsTrigger value="overview">Overview</TabsTrigger>
                    <TabsTrigger value="tailoring">Tailoring</TabsTrigger>
                    <TabsTrigger value="description">Description</TabsTrigger>
                  </TabsList>

                  <TabsContent value="overview" className="space-y-3 pt-3">
                    <div className="rounded-lg border border-border/60 bg-muted/20 p-3 text-sm text-muted-foreground">
                      {selectedJob.suitabilityReason
                        ? `"${selectedJob.suitabilityReason}"`
                        : "No suitability summary yet."}
                    </div>

                    <div className="grid gap-3 text-sm sm:grid-cols-2">
                      <div>
                        <div className="text-xs text-muted-foreground">Discipline</div>
                        <div className="font-medium">{selectedJob.disciplines || "Not set"}</div>
                      </div>
                      <div>
                        <div className="text-xs text-muted-foreground">Job function</div>
                        <div className="font-medium">{selectedJob.jobFunction || "Not set"}</div>
                      </div>
                      <div>
                        <div className="text-xs text-muted-foreground">Job level</div>
                        <div className="font-medium">{selectedJob.jobLevel || "Not set"}</div>
                      </div>
                      <div>
                        <div className="text-xs text-muted-foreground">Job type</div>
                        <div className="font-medium">{selectedJob.jobType || "Not set"}</div>
                      </div>
                    </div>
                  </TabsContent>

                  <TabsContent value="tailoring" className="pt-3">
                    <TailoringEditor job={selectedJob} onUpdate={loadJobs} />
                  </TabsContent>

                  <TabsContent value="description" className="space-y-3 pt-3">
                    <div className="flex items-center justify-between">
                      <div className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
                        Job description
                      </div>
                      <DropdownMenu>
                        <DropdownMenuTrigger asChild>
                          <Button size="icon" variant="ghost" aria-label="Description actions">
                            <MoreHorizontal className="h-4 w-4" />
                          </Button>
                        </DropdownMenuTrigger>
                        <DropdownMenuContent align="end">
                          {!isEditingDescription ? (
                            <DropdownMenuItem onSelect={() => setIsEditingDescription(true)}>
                              Edit description
                            </DropdownMenuItem>
                          ) : (
                            <>
                              <DropdownMenuItem onSelect={handleSaveDescription} disabled={isSavingDescription}>
                                {isSavingDescription ? "Saving..." : "Save changes"}
                              </DropdownMenuItem>
                              <DropdownMenuItem
                                onSelect={() => {
                                  setIsEditingDescription(false);
                                  setEditedDescription(selectedJob.jobDescription || "");
                                }}
                                disabled={isSavingDescription}
                              >
                                Cancel edit
                              </DropdownMenuItem>
                            </>
                          )}
                        </DropdownMenuContent>
                      </DropdownMenu>
                    </div>

                    <div className="rounded-lg border border-border/60 bg-muted/10 p-3 text-sm text-muted-foreground">
                      {isEditingDescription ? (
                        <Textarea
                          value={editedDescription}
                          onChange={(event) => setEditedDescription(event.target.value)}
                          className="min-h-[240px] font-mono text-sm leading-relaxed"
                          placeholder="Enter job description..."
                        />
                      ) : (
                        <div className="whitespace-pre-wrap leading-relaxed">
                          <ReactMarkdown remarkPlugins={[remarkGfm]}>{description}</ReactMarkdown>
                        </div>
                      )}
                    </div>
                  </TabsContent>
                </Tabs>
              </div>
            )}
          </div>
        </section>
      </main>
    </>
  );
};
