"use client";

import { useEffect, useMemo, useState, type FormEvent } from "react";
import Link from "next/link";
import { Plus, RefreshCw, Search } from "lucide-react";
import { toast } from "react-hot-toast";
import { Button } from "@/components/ui/button";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Panel } from "@/components/shared/panel";
import { ticketCategories, ticketPriorities, type CreateTicketValues, type TicketCategory, type TicketPriority, type TicketListItem } from "./types";
import { fetchTickets, submitTicket } from "./client-api";

type StatusFilter = "all" | "open" | "in-progress" | "closed";
const pageSize = 10;

function messageFrom(error: unknown, fallback: string) {
  return error instanceof Error && error.message.trim() ? error.message : fallback;
}

function statusGroup(status: string): StatusFilter {
  const normalized = status.trim().toUpperCase().replace(/[ -]/g, "_");
  if (normalized === "OPEN" || normalized === "NEW") return "open";
  if (normalized === "IN_PROGRESS" || normalized === "PENDING") return "in-progress";
  if (normalized === "CLOSED" || normalized === "RESOLVED" || normalized === "DONE") return "closed";
  return "all";
}

function statusClass(status: string) {
  const group = statusGroup(status);
  if (group === "open") return "border-emerald-500/25 bg-emerald-500/10 text-emerald-500";
  if (group === "in-progress") return "border-amber-500/25 bg-amber-500/10 text-amber-500";
  if (group === "closed") return "border-muted bg-muted text-muted-foreground";
  return "border-primary/25 bg-primary/10 text-primary";
}

function formatDate(value: string) {
  if (!value) return "—";
  const date = new Date(value);
  return Number.isNaN(date.getTime())
    ? value
    : new Intl.DateTimeFormat("en-GB", { dateStyle: "medium", timeStyle: "short" }).format(date);
}

function categoryLabel(category: string) {
  return category.replaceAll("_", " ").toLowerCase().replace(/\b\w/g, (letter) => letter.toUpperCase());
}

export function TicketsView() {
  const [tickets, setTickets] = useState<TicketListItem[]>([]);
  const [refreshVersion, setRefreshVersion] = useState(0);
  const [loadedRefreshVersion, setLoadedRefreshVersion] = useState(-1);
  const [loadFailure, setLoadFailure] = useState<{ version: number; message: string } | null>(null);
  const [search, setSearch] = useState("");
  const [statusFilter, setStatusFilter] = useState<StatusFilter>("all");
  const [page, setPage] = useState(1);
  const [createOpen, setCreateOpen] = useState(false);
  const [saving, setSaving] = useState(false);
  const [draft, setDraft] = useState<CreateTicketValues>({
    subject: "",
    description: "",
    category: "ACCOUNT",
    priority: "LOW",
  });
  const loading = loadedRefreshVersion !== refreshVersion;
  const loadError = loadFailure?.version === refreshVersion ? loadFailure.message : "";

  useEffect(() => {
    const controller = new AbortController();
    void fetchTickets(controller.signal)
      .then((result) => {
        if (controller.signal.aborted) return;
        setTickets(result);
        setLoadFailure(null);
      })
      .catch((error: unknown) => {
        if (!controller.signal.aborted) {
          setTickets([]);
          setLoadFailure({ version: refreshVersion, message: messageFrom(error, "Unable to load tickets. Please try again.") });
        }
      })
      .finally(() => {
        if (!controller.signal.aborted) setLoadedRefreshVersion(refreshVersion);
      });
    return () => controller.abort();
  }, [refreshVersion]);

  const filteredTickets = useMemo(() => {
    const query = search.trim().toLocaleLowerCase();
    return tickets.filter((ticket) => {
      const matchesSearch = !query || [ticket.ticketNumber, ticket.subject, ticket.category, ticket.status]
        .some((value) => value.toLocaleLowerCase().includes(query));
      const matchesStatus = statusFilter === "all" || statusGroup(ticket.status) === statusFilter;
      return matchesSearch && matchesStatus;
    });
  }, [search, statusFilter, tickets]);
  const totalPages = Math.max(1, Math.ceil(filteredTickets.length / pageSize));
  const visibleTickets = filteredTickets.slice((page - 1) * pageSize, page * pageSize);

  function openCreateDialog() {
    setDraft({ subject: "", description: "", category: "ACCOUNT", priority: "LOW" });
    setCreateOpen(true);
  }

  async function handleCreate(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    setSaving(true);
    try {
      const message = await submitTicket(draft);
      setCreateOpen(false);
      toast.success(message || "Ticket created successfully.");
      setPage(1);
      setRefreshVersion((version) => version + 1);
    } catch (error) {
      toast.error(messageFrom(error, "Unable to create the ticket. Please try again."));
    } finally {
      setSaving(false);
    }
  }

  function setCategory(value: string) {
    if (ticketCategories.includes(value as TicketCategory)) {
      setDraft((current) => ({ ...current, category: value as TicketCategory }));
    }
  }

  function setPriority(value: string) {
    if (ticketPriorities.includes(value as TicketPriority)) {
      setDraft((current) => ({ ...current, priority: value as TicketPriority }));
    }
  }

  return (
    <>
      <Panel className="overflow-hidden p-0">
        <div className="flex flex-col gap-3 border-b border-border px-5 py-4 sm:flex-row sm:items-start sm:justify-between md:px-6">
          <div>
            <h2 className="text-lg font-semibold">Support tickets ({tickets.length})</h2>
            <p className="mt-1 text-sm text-muted-foreground">View, track, and respond to support tickets for your tenant.</p>
          </div>
          <Button onClick={openCreateDialog}>
            <Plus aria-hidden="true" />
            Create ticket
          </Button>
        </div>

        <div className="flex flex-col gap-3 px-5 py-4 md:px-6 lg:flex-row lg:items-center lg:justify-between">
          <div className="relative w-full lg:max-w-sm">
            <Search className="pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-muted-foreground" aria-hidden="true" />
            <Input
              aria-label="Search tickets"
              value={search}
              onChange={(event) => { setSearch(event.target.value); setPage(1); }}
              placeholder="Search by ticket or subject..."
              className="pl-9"
            />
          </div>
          <div className="flex flex-wrap items-center gap-2">
            {([
              ["all", "All"],
              ["open", "Open"],
              ["in-progress", "In progress"],
              ["closed", "Closed"],
            ] as const).map(([value, label]) => (
              <Button
                key={value}
                type="button"
                variant={statusFilter === value ? "secondary" : "outline"}
                size="sm"
                onClick={() => { setStatusFilter(value); setPage(1); }}
              >
                {label}
              </Button>
            ))}
            <Button
              type="button"
              variant="outline"
              size="icon"
              aria-label="Refresh tickets"
              title="Refresh tickets"
              disabled={loading}
              onClick={() => setRefreshVersion((version) => version + 1)}
            >
              <RefreshCw className={loading ? "animate-spin" : ""} aria-hidden="true" />
            </Button>
          </div>
        </div>

        {loadError && (
          <div role="alert" className="mx-5 mb-4 flex flex-wrap items-center justify-between gap-3 rounded-lg border border-destructive/40 bg-destructive/5 px-4 py-3 text-sm text-destructive md:mx-6">
            <span>{loadError}</span>
            <Button type="button" variant="outline" size="sm" onClick={() => setRefreshVersion((version) => version + 1)}>
              Retry
            </Button>
          </div>
        )}

        <div className="overflow-x-auto px-5 pb-5 md:px-6">
          <table className="w-full min-w-[760px] border-collapse text-sm">
            <thead>
              <tr className="border-y border-border text-left text-muted-foreground">
                <th scope="col" className="px-4 py-3 font-medium">Ticket</th>
                <th scope="col" className="px-4 py-3 font-medium">Subject</th>
                <th scope="col" className="px-4 py-3 font-medium">Category</th>
                <th scope="col" className="px-4 py-3 font-medium">Priority</th>
                <th scope="col" className="px-4 py-3 font-medium">Status</th>
                <th scope="col" className="px-4 py-3 font-medium">Created</th>
              </tr>
            </thead>
            <tbody className="divide-y divide-border">
              {loading ? (
                <tr><td colSpan={6} className="px-4 py-12 text-center text-muted-foreground">Loading tickets…</td></tr>
              ) : loadError ? (
                <tr><td colSpan={6} className="px-4 py-12 text-center text-muted-foreground">Ticket list is unavailable.</td></tr>
              ) : visibleTickets.length === 0 ? (
                <tr><td colSpan={6} className="px-4 py-12 text-center text-muted-foreground">{tickets.length ? "No tickets match these filters." : "No tickets yet."}</td></tr>
              ) : visibleTickets.map((ticket) => (
                <tr key={ticket.id} className="transition-colors hover:bg-muted/40">
                  <td className="whitespace-nowrap px-4 py-4 font-medium">
                    <Link className="text-white hover:underline" href={`/support/${encodeURIComponent(ticket.id)}`}>{ticket.ticketNumber}</Link>
                  </td>
                  <td className="max-w-[340px] px-4 py-4">
                    <Link className="block truncate font-medium hover:text-primary" href={`/support/${encodeURIComponent(ticket.id)}`}>{ticket.subject}</Link>
                    {ticket.tenant && <span className="mt-1 block text-xs text-muted-foreground">{ticket.tenant}</span>}
                  </td>
                  <td className="whitespace-nowrap px-4 py-4 text-muted-foreground">{categoryLabel(ticket.category)}</td>
                  <td className="whitespace-nowrap px-4 py-4 text-muted-foreground">{categoryLabel(ticket.priority)}</td>
                  <td className="whitespace-nowrap px-4 py-4">
                    <span className={`inline-flex rounded-full border px-2.5 py-1 text-xs font-medium ${statusClass(ticket.status)}`}>{categoryLabel(ticket.status)}</span>
                  </td>
                  <td className="whitespace-nowrap px-4 py-4 text-muted-foreground">{formatDate(ticket.createdAt)}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>

        <div className="flex flex-col gap-3 border-t border-border px-5 py-4 text-sm text-muted-foreground sm:flex-row sm:items-center sm:justify-between md:px-6">
          <span>Showing {filteredTickets.length ? (page - 1) * pageSize + 1 : 0}–{Math.min(page * pageSize, filteredTickets.length)} of {filteredTickets.length} tickets</span>
          <div className="flex items-center gap-2">
            <Button type="button" variant="outline" size="sm" disabled={page <= 1} onClick={() => setPage((current) => Math.max(1, current - 1))}>Previous</Button>
            <span className="px-1">{page} / {totalPages}</span>
            <Button type="button" variant="outline" size="sm" disabled={page >= totalPages} onClick={() => setPage((current) => Math.min(totalPages, current + 1))}>Next</Button>
          </div>
        </div>
      </Panel>

      <Dialog open={createOpen} onOpenChange={(open) => { if (!saving) setCreateOpen(open); }}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Create support ticket</DialogTitle>
            <DialogDescription>Describe the issue and choose a category and priority.</DialogDescription>
          </DialogHeader>
          <form className="space-y-4" onSubmit={handleCreate}>
            <label className="block space-y-1.5">
              <span className="text-sm font-medium">Subject</span>
              <Input required maxLength={200} value={draft.subject} onChange={(event) => setDraft((current) => ({ ...current, subject: event.target.value }))} placeholder="Short summary of the issue" />
            </label>
            <label className="block space-y-1.5">
              <span className="text-sm font-medium">Description</span>
              <textarea required maxLength={10_000} rows={5} value={draft.description} onChange={(event) => setDraft((current) => ({ ...current, description: event.target.value }))} placeholder="Add details that will help the team resolve the issue." className="w-full resize-y rounded-lg border border-input bg-transparent px-4 py-3 text-sm outline-none transition-colors placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50" />
            </label>
            <div className="grid gap-4 sm:grid-cols-2">
              <label className="block space-y-1.5">
                <span className="text-sm font-medium">Category</span>
                <select value={draft.category} onChange={(event) => setCategory(event.target.value)} className="h-11 w-full rounded-lg border border-input bg-background px-3 text-sm outline-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50">
                  {ticketCategories.map((category) => <option key={category} value={category}>{categoryLabel(category)}</option>)}
                </select>
              </label>
              <label className="block space-y-1.5">
                <span className="text-sm font-medium">Priority</span>
                <select value={draft.priority} onChange={(event) => setPriority(event.target.value)} className="h-11 w-full rounded-lg border border-input bg-background px-3 text-sm outline-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50">
                  {ticketPriorities.map((priority) => <option key={priority} value={priority}>{categoryLabel(priority)}</option>)}
                </select>
              </label>
            </div>
            <DialogFooter>
              <Button type="button" variant="outline" disabled={saving} onClick={() => setCreateOpen(false)}>Cancel</Button>
              <Button type="submit" disabled={saving || !draft.subject.trim() || !draft.description.trim()}>{saving ? "Creating…" : "Create ticket"}</Button>
            </DialogFooter>
          </form>
        </DialogContent>
      </Dialog>
    </>
  );
}
