"use client";

import { useEffect, useState, type FormEvent } from "react";
import Link from "next/link";
import { ArrowLeft, Check, MessageCircle, RefreshCw, Send } 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 { Panel } from "@/components/shared/panel";
import { StatusBadge } from "@/components/shared/status-badge";
import { closeTicketRequest, fetchTicket, submitTicketReply } from "./client-api";
import type { TicketDetail } from "./types";

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

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 label(value: string) {
  return value.replaceAll("_", " ").toLowerCase().replace(/\b\w/g, (letter) => letter.toUpperCase());
}

function isTenantMessage(sender: string) {
  return ["TENANT", "YOU"].includes(sender.trim().toUpperCase());
}

function senderInitials(sender: string) {
  const words = label(sender).split(/\s+/).filter(Boolean);
  if (!words.length) return "?";
  return words.length > 1
    ? `${words[0][0]}${words[words.length - 1][0]}`.toUpperCase()
    : words[0].slice(0, 2).toUpperCase();
}

function statusTone(status: string): "success" | "warning" | "neutral" {
  const normalized = status.toUpperCase();
  if (["OPEN", "NEW"].includes(normalized)) return "success";
  if (["IN_PROGRESS", "PENDING"].includes(normalized)) return "warning";
  return "neutral";
}

export function TicketDetailView({ id }: { id: string }) {
  const [ticket, setTicket] = useState<TicketDetail | null>(null);
  const [refreshVersion, setRefreshVersion] = useState(0);
  const requestKey = `${id}:${refreshVersion}`;
  const [loadedRequestKey, setLoadedRequestKey] = useState("");
  const [loadFailure, setLoadFailure] = useState<{ key: string; message: string } | null>(null);
  const [reply, setReply] = useState("");
  const [replying, setReplying] = useState(false);
  const [closeOpen, setCloseOpen] = useState(false);
  const [closing, setClosing] = useState(false);
  const loading = loadedRequestKey !== requestKey;
  const loadError = loadFailure?.key === requestKey ? loadFailure.message : "";

  useEffect(() => {
    const controller = new AbortController();
    void fetchTicket(id, controller.signal)
      .then((result) => {
        if (!controller.signal.aborted) {
          setTicket(result);
          setLoadFailure(null);
        }
      })
      .catch((error: unknown) => {
        if (!controller.signal.aborted) {
          setTicket(null);
          setLoadFailure({ key: requestKey, message: messageFrom(error, "Unable to load ticket details. Please try again.") });
        }
      })
      .finally(() => {
        if (!controller.signal.aborted) setLoadedRequestKey(requestKey);
      });
    return () => controller.abort();
  }, [id, refreshVersion, requestKey]);

  async function handleReply(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!ticket || !reply.trim()) return;
    const submittedReply = reply.trim();
    const previousMessageKeys = new Set(ticket.messages.map((item) =>
      JSON.stringify([item.sender, item.message, item.createdAt]),
    ));
    const submittedAt = new Date().toISOString();
    setReplying(true);
    try {
      const message = await submitTicketReply(ticket.id, submittedReply);
      setReply("");
      toast.success(message || "Reply sent successfully.");
      const sentReply = {
        id: `local-reply-${Date.now()}`,
        message: submittedReply,
        sender: "You",
        createdAt: submittedAt,
      };
      try {
        const updated = await fetchTicket(ticket.id);
        const replyReturnedByService = updated.messages.some(
          (item) => item.message === submittedReply && !previousMessageKeys.has(
            JSON.stringify([item.sender, item.message, item.createdAt]),
          ),
        );
        setTicket({
          ...updated,
          messages: replyReturnedByService ? updated.messages : [...updated.messages, sentReply],
        });
      } catch {
        setTicket((current) => current && current.id === ticket.id
          ? { ...current, messages: [...current.messages, sentReply] }
          : current);
        toast.error("Reply was sent, but the conversation could not be refreshed.");
      }
    } catch (error) {
      toast.error(messageFrom(error, "Unable to send the reply. Please try again."));
    } finally {
      setReplying(false);
    }
  }

  async function confirmClose() {
    if (!ticket) return;
    setClosing(true);
    try {
      const message = await closeTicketRequest(ticket.id);
      setTicket((current) => current ? { ...current, status: "CLOSED", closedAt: new Date().toISOString() } : current);
      setCloseOpen(false);
      toast.success(message || "Ticket closed successfully.");
    } catch (error) {
      toast.error(messageFrom(error, "Unable to close the ticket. Please try again."));
    } finally {
      setClosing(false);
    }
  }

  const closed = ticket?.status.trim().toUpperCase() === "CLOSED";

  if (loading) {
    return <Panel className="p-10 text-center text-muted-foreground">Loading ticket details…</Panel>;
  }

  if (loadError || !ticket) {
    return (
      <Panel className="p-8 text-center">
        <p role="alert" className="text-destructive">{loadError || "Ticket not found."}</p>
        <div className="mt-4 flex justify-center gap-2">
          <Button asChild variant="outline"><Link href="/support"><ArrowLeft aria-hidden="true" /> Back to tickets</Link></Button>
          <Button type="button" variant="outline" onClick={() => setRefreshVersion((version) => version + 1)}><RefreshCw aria-hidden="true" /> Retry</Button>
        </div>
      </Panel>
    );
  }

  return (
    <div className="space-y-5">
      <div className="flex flex-wrap items-center justify-between gap-3">
        <Button asChild variant="outline"><Link href="/support"><ArrowLeft aria-hidden="true" /> All tickets</Link></Button>
        <div className="flex items-center gap-2">
          <Button type="button" variant="outline" size="icon" aria-label="Refresh ticket" title="Refresh ticket" onClick={() => setRefreshVersion((version) => version + 1)}>
            <RefreshCw aria-hidden="true" />
          </Button>
          {!closed && <Button type="button" variant="outline" onClick={() => setCloseOpen(true)}><Check aria-hidden="true" /> Close ticket</Button>}
        </div>
      </div>

      <Panel className="overflow-hidden p-0">
        <div className="px-5 py-5 md:px-6">
          <div className="flex flex-wrap items-start justify-between gap-4">
            <div className="min-w-0">
              <p className="text-sm font-medium text-primary">{ticket.ticketNumber}</p>
              <h2 className="mt-1 break-words text-xl font-semibold">{ticket.subject}</h2>
              {ticket.description && (
                <p className="mt-1 whitespace-pre-wrap text-sm leading-6 text-muted-foreground">{ticket.description}</p>
              )}
            </div>
            <StatusBadge tone={statusTone(ticket.status)}>{label(ticket.status)}</StatusBadge>
          </div>
        </div>
        <dl className="grid grid-cols-2 gap-x-6 gap-y-4 border-t border-border px-5 py-4 sm:grid-cols-3 md:px-6 xl:grid-cols-5">
          <div>
            <dt className="text-xs text-muted-foreground">Tenant</dt>
            <dd className="mt-1 break-words text-sm font-medium">{ticket.tenant || "—"}</dd>
          </div>
          <div>
            <dt className="text-xs text-muted-foreground">Category</dt>
            <dd className="mt-1 text-sm font-medium">{label(ticket.category)}</dd>
          </div>
          <div>
            <dt className="text-xs text-muted-foreground">Priority</dt>
            <dd className="mt-1 text-sm font-medium">{label(ticket.priority)}</dd>
          </div>
          <div>
            <dt className="text-xs text-muted-foreground">Created</dt>
            <dd className="mt-1 text-sm font-medium">{formatDate(ticket.createdAt)}</dd>
          </div>
          <div>
            <dt className="text-xs text-muted-foreground">Last updated</dt>
            <dd className="mt-1 text-sm font-medium">{formatDate(ticket.updatedAt)}</dd>
          </div>
        </dl>
      </Panel>

      <Panel title="Conversation" description={`${ticket.messages.length} ${ticket.messages.length === 1 ? "message" : "messages"}`}>
        {ticket.messages.length ? (
          <ol className="relative space-y-3 before:absolute before:bottom-5 before:left-5 before:top-5 before:w-px before:bg-border">
            {[...ticket.messages]
              .sort((left, right) => Date.parse(left.createdAt) - Date.parse(right.createdAt))
              .map((item) => {
                const fromTenant = isTenantMessage(item.sender);
                const sender = fromTenant ? "You" : label(item.sender);
                return (
                  <li key={item.id} className="relative flex min-w-0 items-start gap-3 md:gap-4">
                    <span
                      aria-hidden="true"
                      className={`z-10 flex size-10 shrink-0 items-center justify-center rounded-full border border-border bg-background text-xs font-semibold ${fromTenant ? "text-primary" : "text-muted-foreground"}`}
                    >
                      {senderInitials(sender)}
                    </span>
                    <article className="min-w-0 flex-1 rounded-lg border border-border/70 bg-muted/10 px-4 py-3">
                      <div className="mb-1 flex flex-wrap items-center justify-between gap-x-4 gap-y-1">
                        <span className={`text-sm font-semibold ${fromTenant ? "text-primary" : "text-foreground"}`}>
                          {sender}
                        </span>
                        <time className="text-xs text-muted-foreground">{formatDate(item.createdAt)}</time>
                      </div>
                      <p className="whitespace-pre-wrap break-words text-sm leading-6">{item.message}</p>
                    </article>
                  </li>
                );
              })}
          </ol>
        ) : (
          <div className="flex min-h-28 flex-col items-center justify-center gap-2 text-center text-muted-foreground">
            <MessageCircle aria-hidden="true" className="size-5" />
            <p className="text-sm">No replies yet.</p>
          </div>
        )}
      </Panel>

      <Panel title="Reply" description={closed ? "This ticket is closed." : "Send a message to continue the conversation."}>
        <form className="space-y-3" onSubmit={handleReply}>
          <label className="sr-only" htmlFor="ticket-reply">Reply message</label>
          <textarea
            id="ticket-reply"
            rows={4}
            maxLength={10_000}
            value={reply}
            onChange={(event) => setReply(event.target.value)}
            disabled={closed || replying}
            placeholder={closed ? "Closed tickets cannot receive replies." : "Write your reply…"}
            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 disabled:cursor-not-allowed disabled:opacity-60"
          />
          <div className="flex justify-end">
            <Button type="submit" disabled={closed || replying || !reply.trim()}>
              <Send aria-hidden="true" />
              {replying ? "Sending…" : "Send reply"}
            </Button>
          </div>
        </form>
      </Panel>

      <Dialog open={closeOpen} onOpenChange={(open) => { if (!closing) setCloseOpen(open); }}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Close this ticket?</DialogTitle>
            <DialogDescription>Ticket {ticket.ticketNumber} will be marked closed. You can still review its conversation.</DialogDescription>
          </DialogHeader>
          <DialogFooter>
            <Button type="button" variant="outline" disabled={closing} onClick={() => setCloseOpen(false)}>Cancel</Button>
            <Button type="button" disabled={closing} onClick={() => void confirmClose()}>{closing ? "Closing…" : "Close ticket"}</Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
