// @File: src/pages/Tickets.tsx
// @Desc: Real WHMCS-backed ticket system for the signed-in client.
//        - Lists the client's tickets (GET  /api/v1/whmcs/tickets)
//        - Shows a selected ticket with all replies
//                                   (GET  /api/v1/whmcs/tickets/:id)
//        - Lets the client post a reply
//                                   (POST /api/v1/whmcs/tickets/:id/reply)
//        - Lets the client open a new ticket
//                                   (POST /api/v1/whmcs/tickets)
//        - Loads available departments
//                                   (GET  /api/v1/whmcs/support-departments)
//
//        All demo / fake data has been removed. If the user is not signed in
//        we bounce them to the login page (same pattern as the dashboard).
import { useCallback, useEffect, useMemo, useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import {
  TicketCheck,
  Search,
  Plus,
  Send,
  ArrowLeft,
  User,
  Clock,
  Tag,
  Loader2,
  AlertCircle,
  RefreshCw,
} from "lucide-react";
import { client } from "@/lib/api";
import { useUserProfile } from "@/hooks/useUserProfile";
import { summarizeTicket, type TicketSummary as AiTicketSummary } from "@/lib/notifications";
import { Sparkles } from "lucide-react";

interface TicketSummary {
  id: number;
  tid?: string | null;
  subject?: string | null;
  status?: string | null;
  priority?: string | null;
  department?: string | null;
  lastreply?: string | null;
}

interface TicketMessage {
  id?: number | null;
  name?: string | null;
  email?: string | null;
  date?: string | null;
  message?: string | null;
  is_staff?: boolean;
  attachments?: string[];
}

interface TicketDetail extends TicketSummary {
  date?: string | null;
  department_id?: number | null;
  messages?: TicketMessage[];
}

interface Department {
  id: number;
  name: string;
}

const STATUSES = ["All", "Open", "Answered", "Customer-Reply", "In Progress", "On Hold", "Closed"];
const PRIORITIES = ["All", "High", "Medium", "Low"];

function statusBadgeClass(status?: string | null): string {
  const s = (status || "").toLowerCase();
  if (["open", "answered"].some((k) => s.includes(k))) return "bg-emerald-100 text-emerald-700";
  if (["in progress", "customer-reply", "customer reply"].some((k) => s.includes(k))) return "bg-blue-100 text-blue-700";
  if (["on hold", "pending"].some((k) => s.includes(k))) return "bg-amber-100 text-amber-700";
  if (["closed", "resolved"].some((k) => s.includes(k))) return "bg-slate-200 text-slate-700";
  return "bg-slate-100 text-slate-500";
}

function priorityBadgeClass(p?: string | null): string {
  const s = (p || "").toLowerCase();
  if (s === "high") return "bg-rose-100 text-rose-700 border-rose-200";
  if (s === "medium") return "bg-amber-100 text-amber-700 border-amber-200";
  if (s === "low") return "bg-slate-100 text-slate-700 border-slate-200";
  return "bg-slate-100 text-slate-700 border-slate-200";
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function errorMessage(err: any, fallback: string): string {
  return (
    err?.response?.data?.detail ||
    err?.response?.data?.message ||
    err?.message ||
    fallback
  );
}

export default function Tickets() {
  const navigate = useNavigate();
  const { loading: authLoading, authed } = useUserProfile();
  const [aiSummary, setAiSummary] = useState<AiTicketSummary | null>(null);
  const [aiSummaryLoading, setAiSummaryLoading] = useState(false);
  const [aiSummaryError, setAiSummaryError] = useState<string | null>(null);

  const handleSummarizeTicket = useCallback(
    async (ticketId: number, force = false) => {
      if (!ticketId) return;
      setAiSummaryLoading(true);
      setAiSummaryError(null);
      try {
        const s = await summarizeTicket(ticketId, { force });
        if (s) {
          setAiSummary(s);
        } else {
          setAiSummaryError("Could not generate summary right now. Please try again.");
        }
      } catch (e: any) {
        setAiSummaryError(e?.message || "Summary failed");
      } finally {
        setAiSummaryLoading(false);
      }
    },
    [],
  );

  const [tickets, setTickets] = useState<TicketSummary[]>([]);
  const [ticketsLoading, setTicketsLoading] = useState(true);
  const [ticketsError, setTicketsError] = useState<string | null>(null);

  const [selectedId, setSelectedId] = useState<number | null>(null);
  const [detail, setDetail] = useState<TicketDetail | null>(null);
  const [detailLoading, setDetailLoading] = useState(false);
  const [detailError, setDetailError] = useState<string | null>(null);

  const [reply, setReply] = useState("");
  const [sendingReply, setSendingReply] = useState(false);

  const [statusFilter, setStatusFilter] = useState("All");
  const [priorityFilter, setPriorityFilter] = useState("All");
  const [query, setQuery] = useState("");

  const [showNew, setShowNew] = useState(false);
  const [departments, setDepartments] = useState<Department[]>([]);
  const [creating, setCreating] = useState(false);
  const [createError, setCreateError] = useState<string | null>(null);
  const [newSubject, setNewSubject] = useState("");
  const [newMessage, setNewMessage] = useState("");
  const [newDeptId, setNewDeptId] = useState<number | "">("");
  const [newPriority, setNewPriority] = useState<"Low" | "Medium" | "High">("Medium");

  // Redirect to /login if unauthenticated.
  useEffect(() => {
    if (!authLoading && !authed) navigate("/login", { replace: true });
  }, [authLoading, authed, navigate]);

  // --- List ------------------------------------------------------------------
  //
  // Wrap the ticket-list fetch with a small retry loop so a transient HTML
  // "503 Temporarily Unavailable" response from the platform proxy (which
  // happens during cold-starts / service restarts) is not surfaced to users
  // as a hard error. We only set `ticketsError` once all retries are
  // exhausted.
  const loadTickets = useCallback(async () => {
    setTicketsLoading(true);
    setTicketsError(null);

    const sleep = (ms: number) =>
      new Promise<void>((resolve) => setTimeout(resolve, ms));

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const isTransientProxyError = (res: any): boolean => {
      if (!res) return true;
      const status = res?.status;
      if (status === 502 || status === 503 || status === 504) return true;
      const data = res?.data;
      if (
        typeof data === "string" &&
        data.trim().toLowerCase().startsWith("<!doctype")
      ) {
        return true;
      }
      return false;
    };

    const maxAttempts = 3;
    let lastErr: unknown = null;
    for (let attempt = 1; attempt <= maxAttempts; attempt++) {
      try {
        const res = await client.apiCall.invoke({
          url: "/api/v1/whmcs/tickets",
          method: "GET",
          data: {},
        });
        if (isTransientProxyError(res)) {
          lastErr = new Error("Service temporarily unavailable.");
          if (attempt < maxAttempts) {
            await sleep(400 * attempt);
            continue;
          }
          throw lastErr;
        }
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const items: TicketSummary[] =
          ((res as any)?.data?.items as TicketSummary[]) || [];
        setTickets(items);
        setSelectedId((prev) => {
          if (prev && items.some((t) => t.id === prev)) return prev;
          return items[0]?.id ?? null;
        });
        setTicketsLoading(false);
        return;
      } catch (err) {
        lastErr = err;
        if (attempt < maxAttempts) {
          await sleep(400 * attempt);
          continue;
        }
      }
    }
    setTicketsError(
      errorMessage(
        lastErr,
        "Failed to load your tickets. The service is temporarily unavailable, please try again in a moment.",
      ),
    );
    setTicketsLoading(false);
  }, []);

  useEffect(() => {
    if (authed) loadTickets();
  }, [authed, loadTickets]);

  // --- Detail ---------------------------------------------------------------
  const loadDetail = useCallback(async (id: number) => {
    setDetailLoading(true);
    setDetailError(null);
    setDetail(null);
    try {
      const res = await client.apiCall.invoke({
        url: `/api/v1/whmcs/tickets/${id}`,
        method: "GET",
        data: {},
      });
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      const data: TicketDetail | undefined = (res as any)?.data;
      if (!data) throw new Error("Ticket not found.");
      setDetail(data);
    } catch (err) {
      setDetailError(errorMessage(err, "Failed to load this ticket."));
    } finally {
      setDetailLoading(false);
    }
  }, []);

  useEffect(() => {
    if (selectedId) loadDetail(selectedId);
    else setDetail(null);
    setAiSummary(null);
    setAiSummaryError(null);
  }, [selectedId, loadDetail]);

  // --- Departments (for new ticket) -----------------------------------------
  const loadDepartments = useCallback(async () => {
    try {
      const res = await client.apiCall.invoke({
        url: "/api/v1/whmcs/support-departments",
        method: "GET",
        data: {},
      });
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      const items: Department[] = ((res as any)?.data?.items as Department[]) || [];
      setDepartments(items);
      setNewDeptId((prev) => (prev === "" && items[0] ? items[0].id : prev));
    } catch (err) {
      // Non-fatal — the modal will show a message if this fails.
      console.error("Failed to load support departments", err);
      setDepartments([]);
    }
  }, []);

  useEffect(() => {
    if (showNew && departments.length === 0) loadDepartments();
  }, [showNew, departments.length, loadDepartments]);

  // --- Actions --------------------------------------------------------------
  const handleReply = async () => {
    if (!detail || !reply.trim()) return;
    setSendingReply(true);
    try {
      await client.apiCall.invoke({
        url: `/api/v1/whmcs/tickets/${detail.id}/reply`,
        method: "POST",
        data: { message: reply.trim() },
      });
      setReply("");
      await loadDetail(detail.id);
      // Also refresh the list so the "last reply" timestamp updates.
      loadTickets();
    } catch (err) {
      alert(errorMessage(err, "Failed to send reply."));
    } finally {
      setSendingReply(false);
    }
  };

  const handleCreate = async () => {
    setCreateError(null);
    if (!newSubject.trim() || !newMessage.trim() || !newDeptId) {
      setCreateError("Please fill in the department, subject and message.");
      return;
    }
    setCreating(true);
    try {
      const res = await client.apiCall.invoke({
        url: "/api/v1/whmcs/tickets",
        method: "POST",
        data: {
          subject: newSubject.trim(),
          message: newMessage.trim(),
          department_id: Number(newDeptId),
          priority: newPriority,
        },
      });
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      const newId = Number((res as any)?.data?.id) || null;
      setShowNew(false);
      setNewSubject("");
      setNewMessage("");
      await loadTickets();
      if (newId) setSelectedId(newId);
    } catch (err) {
      setCreateError(errorMessage(err, "Failed to open ticket."));
    } finally {
      setCreating(false);
    }
  };

  // --- Derived --------------------------------------------------------------
  const filtered = useMemo(() => {
    const q = query.trim().toLowerCase();
    return tickets.filter((t) => {
      if (statusFilter !== "All" && !(t.status || "").toLowerCase().includes(statusFilter.toLowerCase())) {
        return false;
      }
      if (priorityFilter !== "All" && (t.priority || "").toLowerCase() !== priorityFilter.toLowerCase()) {
        return false;
      }
      if (!q) return true;
      return (
        (t.subject || "").toLowerCase().includes(q) ||
        (t.tid || "").toLowerCase().includes(q) ||
        (t.department || "").toLowerCase().includes(q)
      );
    });
  }, [tickets, statusFilter, priorityFilter, query]);

  // --- Render ---------------------------------------------------------------
  if (authLoading || !authed) {
    return (
      <div className="min-h-screen flex items-center justify-center bg-slate-50 text-slate-600">
        <div className="flex items-center gap-2 text-sm">
          <Loader2 className="w-5 h-5 animate-spin text-[#0b6e3e]" />
          Loading…
        </div>
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-slate-50">
      {/* Top header */}
      <header className="h-16 bg-white border-b border-slate-200 flex items-center justify-between px-6 sticky top-0 z-10">
        <div className="flex items-center gap-3">
          <Link to="/client" className="w-9 h-9 rounded-lg hover:bg-slate-100 flex items-center justify-center">
            <ArrowLeft className="w-4 h-4" />
          </Link>
          <img src="/logo.svg" alt="DoItEasy" className="h-12 md:h-14 w-auto"
            onError={(e) => ((e.target as HTMLImageElement).style.display = "none")} />
          <div className="h-5 w-px bg-slate-200" />
          <div className="flex items-center gap-2">
            <TicketCheck className="w-5 h-5 text-[#0b6e3e]" />
            <h1 className="text-lg font-bold text-slate-900">Support Tickets</h1>
          </div>
        </div>
        <div className="flex items-center gap-2">
          <button
            onClick={loadTickets}
            className="w-9 h-9 rounded-lg hover:bg-slate-100 flex items-center justify-center"
            title="Refresh"
          >
            <RefreshCw className="w-4 h-4 text-slate-600" />
          </button>
          <button
            onClick={() => setShowNew(true)}
            className="px-4 py-2 rounded-md bg-[#0b6e3e] text-white font-bold text-sm hover:bg-[#0a8048] flex items-center gap-2"
          >
            <Plus className="w-4 h-4" /> New Ticket
          </button>
        </div>
      </header>

      {/* Main layout */}
      <div className="max-w-7xl 3xl:max-w-[1680px] 4xl:max-w-[2000px] 5xl:max-w-[2400px] mx-auto p-6 grid lg:grid-cols-[380px_1fr] gap-6">
        {/* TICKET LIST */}
        <div className="bg-white rounded-2xl border border-slate-200 shadow-sm flex flex-col max-h-[80vh]">
          <div className="p-4 border-b border-slate-100 space-y-3">
            <div className="relative">
              <Search className="w-4 h-4 absolute left-3 top-1/2 -translate-y-1/2 text-slate-400" />
              <input
                value={query}
                onChange={(e) => setQuery(e.target.value)}
                placeholder="Search tickets…"
                className="w-full pl-9 pr-4 py-2 bg-slate-100 rounded-lg text-sm outline-none focus:ring-2 focus:ring-[#0b6e3e]/20"
              />
            </div>
            <div className="flex gap-2 text-xs">
              <select
                value={statusFilter}
                onChange={(e) => setStatusFilter(e.target.value)}
                className="flex-1 border border-slate-200 rounded-md px-2 py-1.5 bg-white"
              >
                {STATUSES.map((s) => <option key={s}>{s}</option>)}
              </select>
              <select
                value={priorityFilter}
                onChange={(e) => setPriorityFilter(e.target.value)}
                className="flex-1 border border-slate-200 rounded-md px-2 py-1.5 bg-white"
              >
                {PRIORITIES.map((s) => <option key={s}>{s}</option>)}
              </select>
            </div>
          </div>

          <div className="overflow-y-auto divide-y divide-slate-100">
            {ticketsLoading ? (
              <div className="p-8 text-center text-sm text-slate-500">
                <Loader2 className="w-4 h-4 animate-spin inline mr-2" />
                Loading your tickets…
              </div>
            ) : ticketsError ? (
              <div className="p-6 text-sm text-red-700 bg-red-50 border-b border-red-100 flex items-start gap-2">
                <AlertCircle className="w-4 h-4 mt-0.5 shrink-0" />
                <div>
                  <div className="font-semibold">Could not load tickets.</div>
                  <div className="text-xs mt-1">{ticketsError}</div>
                  <button
                    onClick={loadTickets}
                    className="mt-2 text-xs font-semibold text-[#0b6e3e] hover:underline"
                  >
                    Retry
                  </button>
                </div>
              </div>
            ) : filtered.length === 0 ? (
              <div className="p-10 text-center text-slate-500 text-sm">
                {tickets.length === 0
                  ? "You don't have any tickets yet."
                  : "No tickets match your filters."}
              </div>
            ) : (
              filtered.map((t) => (
                <button
                  key={t.id}
                  onClick={() => setSelectedId(t.id)}
                  className={`w-full text-left p-4 hover:bg-slate-50 transition ${
                    selectedId === t.id
                      ? "bg-[#0b6e3e]/5 border-l-4 border-[#0b6e3e]"
                      : "border-l-4 border-transparent"
                  }`}
                >
                  <div className="flex items-center justify-between mb-1">
                    <span className="text-xs font-bold text-slate-500">
                      #{t.tid || t.id}
                    </span>
                    <span
                      className={`text-[10px] font-bold px-2 py-0.5 rounded-full border ${priorityBadgeClass(t.priority)}`}
                    >
                      {t.priority || "—"}
                    </span>
                  </div>
                  <div className="font-semibold text-slate-900 text-sm line-clamp-2">
                    {t.subject || "(no subject)"}
                  </div>
                  <div className="flex items-center justify-between mt-1 text-xs text-slate-500">
                    <span className="truncate">{t.department || "—"}</span>
                    <span className="shrink-0">{t.lastreply || "—"}</span>
                  </div>
                  <span
                    className={`inline-block mt-2 text-[10px] font-semibold px-2 py-0.5 rounded-full ${statusBadgeClass(t.status)}`}
                  >
                    {t.status || "—"}
                  </span>
                </button>
              ))
            )}
          </div>
        </div>

        {/* TICKET DETAIL */}
        <div className="bg-white rounded-2xl border border-slate-200 shadow-sm flex flex-col">
          {selectedId === null ? (
            <div className="flex-1 flex items-center justify-center text-slate-500 p-10 text-sm">
              Select a ticket to view the conversation, or open a new one.
            </div>
          ) : detailLoading ? (
            <div className="flex-1 flex items-center justify-center text-slate-500 p-10">
              <Loader2 className="w-5 h-5 animate-spin text-[#0b6e3e] mr-2" />
              Loading ticket…
            </div>
          ) : detailError ? (
            <div className="flex-1 flex items-center justify-center text-slate-500 p-10">
              <div className="text-center max-w-sm">
                <AlertCircle className="w-8 h-8 mx-auto text-rose-500 mb-2" />
                <div className="font-semibold text-slate-800">Couldn't load this ticket.</div>
                <div className="text-xs text-slate-500 mt-1">{detailError}</div>
                <button
                  onClick={() => selectedId && loadDetail(selectedId)}
                  className="mt-3 px-3 py-1.5 rounded-md border border-slate-200 text-xs font-semibold hover:bg-slate-50"
                >
                  Retry
                </button>
              </div>
            </div>
          ) : detail ? (
            <>
              {/* detail header */}
              <div className="p-5 border-b border-slate-100">
                <div className="flex items-start justify-between gap-4 flex-wrap">
                  <div className="flex-1">
                    <div className="flex items-center gap-2 text-xs text-slate-500 mb-1">
                      <span className="font-bold">#{detail.tid || detail.id}</span>
                      <span className={`text-[10px] font-bold px-2 py-0.5 rounded-full ${statusBadgeClass(detail.status)}`}>
                        {detail.status || "—"}
                      </span>
                      <span
                        className={`text-[10px] font-bold px-2 py-0.5 rounded-full border ${priorityBadgeClass(detail.priority)}`}
                      >
                        {detail.priority || "—"}
                      </span>
                    </div>
                    <h2 className="text-xl font-bold text-slate-900">
                      {detail.subject || "(no subject)"}
                    </h2>
                  </div>
                </div>
                <div className="grid grid-cols-2 md:grid-cols-3 gap-3 mt-4 text-xs">
                  <div className="flex items-center gap-2 text-slate-600">
                    <Tag className="w-3.5 h-3.5" /> {detail.department || "—"}
                  </div>
                  <div className="flex items-center gap-2 text-slate-600">
                    <Clock className="w-3.5 h-3.5" /> Opened: {detail.date || "—"}
                  </div>
                  <div className="flex items-center gap-2 text-slate-600">
                    <Clock className="w-3.5 h-3.5" /> Last reply: {detail.lastreply || "—"}
                  </div>
                </div>

                {/* AI Summary panel */}
                <div className="mt-4 rounded-xl border border-emerald-200 bg-emerald-50/40 p-3">
                  <div className="flex items-center justify-between gap-2 flex-wrap">
                    <div className="flex items-center gap-2 text-[13px] font-bold text-emerald-900">
                      <Sparkles className="w-4 h-4" />
                      AI Ticket Summary
                    </div>
                    <div className="flex items-center gap-2">
                      {aiSummary ? (
                        <button
                          type="button"
                          onClick={() => handleSummarizeTicket(detail.id, true)}
                          disabled={aiSummaryLoading}
                          className="text-[11px] font-bold px-2.5 py-1 rounded-md border border-emerald-300 text-emerald-800 hover:bg-emerald-100 disabled:opacity-60"
                        >
                          {aiSummaryLoading ? "Refreshing…" : "Regenerate"}
                        </button>
                      ) : (
                        <button
                          type="button"
                          onClick={() => handleSummarizeTicket(detail.id, false)}
                          disabled={aiSummaryLoading || (detail.messages || []).length === 0}
                          className="text-[11px] font-bold px-2.5 py-1 rounded-md bg-emerald-600 text-white hover:bg-emerald-700 disabled:opacity-60 inline-flex items-center gap-1"
                        >
                          {aiSummaryLoading ? (
                            <>
                              <Loader2 className="w-3 h-3 animate-spin" />
                              Summarizing…
                            </>
                          ) : (
                            <>
                              <Sparkles className="w-3 h-3" />
                              Summarize thread
                            </>
                          )}
                        </button>
                      )}
                    </div>
                  </div>

                  {aiSummaryError ? (
                    <p className="mt-2 text-xs text-red-600">{aiSummaryError}</p>
                  ) : null}

                  {aiSummary ? (
                    <div className="mt-3 space-y-2 text-xs text-slate-700">
                      {aiSummary.tl_dr ? (
                        <p>
                          <span className="font-bold text-slate-900">TL;DR: </span>
                          {aiSummary.tl_dr}
                        </p>
                      ) : null}
                      {aiSummary.key_points && aiSummary.key_points.length > 0 ? (
                        <div>
                          <div className="font-bold text-slate-900 mb-0.5">Key points</div>
                          <ul className="list-disc pl-5 space-y-0.5">
                            {aiSummary.key_points.map((k, idx) => (
                              <li key={idx}>{k}</li>
                            ))}
                          </ul>
                        </div>
                      ) : null}
                      {aiSummary.action_items && aiSummary.action_items.length > 0 ? (
                        <div>
                          <div className="font-bold text-slate-900 mb-0.5">Action items</div>
                          <ul className="list-disc pl-5 space-y-0.5">
                            {aiSummary.action_items.map((a, idx) => (
                              <li key={idx}>{a}</li>
                            ))}
                          </ul>
                        </div>
                      ) : null}
                      {aiSummary.next_step ? (
                        <p>
                          <span className="font-bold text-slate-900">Next step: </span>
                          {aiSummary.next_step}
                        </p>
                      ) : null}
                      <p className="text-[10px] text-slate-400 pt-1">
                        {aiSummary.cached ? "Cached summary" : "Fresh summary"}
                        {aiSummary.model ? ` · ${aiSummary.model}` : ""}
                      </p>
                    </div>
                  ) : !aiSummaryLoading && !aiSummaryError ? (
                    <p className="mt-2 text-xs text-slate-500">
                      Generate a quick AI summary of this ticket thread, including TL;DR,
                      key points, and the next recommended step.
                    </p>
                  ) : null}
                </div>
              </div>

              {/* conversation */}
              <div className="flex-1 p-5 space-y-4 overflow-y-auto max-h-[50vh]">
                {(detail.messages || []).length === 0 ? (
                  <div className="text-sm text-slate-500 text-center py-8">
                    No messages on this ticket yet.
                  </div>
                ) : (
                  (detail.messages || []).map((m, i) => (
                    <div
                      key={m.id ?? i}
                      className={`flex gap-3 ${m.is_staff ? "flex-row-reverse" : ""}`}
                    >
                      <div
                        className={`w-9 h-9 rounded-full flex items-center justify-center text-white font-bold text-sm shrink-0 ${
                          m.is_staff ? "bg-[#0b6e3e]" : "bg-slate-700"
                        }`}
                      >
                        {(m.name || (m.is_staff ? "Staff" : "You")).trim()[0]?.toUpperCase() || <User className="w-4 h-4" />}
                      </div>
                      <div
                        className={`max-w-[75%] ${m.is_staff ? "items-end" : ""} flex flex-col`}
                      >
                        <div
                          className={`rounded-2xl px-4 py-3 text-sm ${
                            m.is_staff
                              ? "bg-[#0b6e3e] text-white"
                              : "bg-slate-100 text-slate-800"
                          }`}
                        >
                          <div className="font-bold mb-1 text-xs opacity-80">
                            {m.name || (m.is_staff ? "Support" : "You")}
                            {m.date ? ` · ${m.date}` : ""}
                          </div>
                          <p className="leading-relaxed whitespace-pre-wrap">
                            {m.message || ""}
                          </p>
                        </div>
                      </div>
                    </div>
                  ))
                )}
              </div>

              {/* reply */}
              <div className="p-4 border-t border-slate-100 bg-slate-50">
                <textarea
                  value={reply}
                  onChange={(e) => setReply(e.target.value)}
                  rows={3}
                  placeholder="Type your reply…"
                  className="w-full p-3 bg-white border border-slate-200 rounded-lg text-sm outline-none focus:ring-2 focus:ring-[#0b6e3e]/20 resize-none"
                  disabled={sendingReply}
                />
                <div className="flex items-center justify-end mt-2">
                  <button
                    onClick={handleReply}
                    disabled={sendingReply || !reply.trim()}
                    className="px-4 py-1.5 text-xs font-bold bg-[#0b6e3e] text-white rounded-md hover:bg-[#0a8048] flex items-center gap-1 disabled:opacity-60 disabled:cursor-not-allowed"
                  >
                    {sendingReply ? (
                      <>
                        <Loader2 className="w-3.5 h-3.5 animate-spin" /> Sending…
                      </>
                    ) : (
                      <>
                        <Send className="w-3.5 h-3.5" /> Send reply
                      </>
                    )}
                  </button>
                </div>
              </div>
            </>
          ) : null}
        </div>
      </div>

      {/* NEW TICKET MODAL */}
      {showNew && (
        <div
          className="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-center justify-center p-4"
          onClick={() => !creating && setShowNew(false)}
        >
          <div
            className="bg-white rounded-2xl max-w-lg w-full p-6"
            onClick={(e) => e.stopPropagation()}
          >
            <div className="flex items-center justify-between mb-4">
              <h3 className="text-xl font-bold">Open New Ticket</h3>
              <button
                onClick={() => !creating && setShowNew(false)}
                className="text-slate-500 hover:text-slate-900 !bg-transparent hover:!bg-transparent"
                disabled={creating}
              >
                ✕
              </button>
            </div>
            <div className="space-y-3">
              <div className="grid grid-cols-2 gap-3">
                <div>
                  <label className="text-xs font-semibold text-slate-700 mb-1 block">
                    Department
                  </label>
                  <select
                    value={newDeptId}
                    onChange={(e) => setNewDeptId(e.target.value ? Number(e.target.value) : "")}
                    className="w-full border border-slate-200 rounded-lg px-3 py-2 text-sm"
                  >
                    <option value="">Select…</option>
                    {departments.map((d) => (
                      <option key={d.id} value={d.id}>
                        {d.name}
                      </option>
                    ))}
                  </select>
                  {departments.length === 0 && (
                    <p className="text-[11px] text-slate-400 mt-1">
                      Loading departments…
                    </p>
                  )}
                </div>
                <div>
                  <label className="text-xs font-semibold text-slate-700 mb-1 block">
                    Priority
                  </label>
                  <select
                    value={newPriority}
                    onChange={(e) => setNewPriority(e.target.value as "Low" | "Medium" | "High")}
                    className="w-full border border-slate-200 rounded-lg px-3 py-2 text-sm"
                  >
                    <option value="Low">Low</option>
                    <option value="Medium">Medium</option>
                    <option value="High">High</option>
                  </select>
                </div>
              </div>
              <div>
                <label className="text-xs font-semibold text-slate-700 mb-1 block">
                  Subject
                </label>
                <input
                  value={newSubject}
                  onChange={(e) => setNewSubject(e.target.value)}
                  className="w-full border border-slate-200 rounded-lg px-3 py-2 text-sm"
                  placeholder="Short summary"
                  maxLength={200}
                />
              </div>
              <div>
                <label className="text-xs font-semibold text-slate-700 mb-1 block">
                  Message
                </label>
                <textarea
                  value={newMessage}
                  onChange={(e) => setNewMessage(e.target.value)}
                  rows={5}
                  className="w-full border border-slate-200 rounded-lg px-3 py-2 text-sm resize-none"
                  placeholder="Describe the issue in detail…"
                />
              </div>
              {createError && (
                <div className="text-xs text-red-700 bg-red-50 border border-red-200 rounded-lg px-3 py-2">
                  {createError}
                </div>
              )}
            </div>
            <div className="flex gap-2 mt-5">
              <button
                onClick={() => !creating && setShowNew(false)}
                className="flex-1 py-2.5 rounded-md border border-slate-200 font-semibold text-sm hover:bg-slate-50 !bg-transparent hover:!bg-slate-50"
                disabled={creating}
              >
                Cancel
              </button>
              <button
                onClick={handleCreate}
                disabled={creating}
                className="flex-1 py-2.5 rounded-md bg-[#0b6e3e] text-white font-bold text-sm hover:bg-[#0a8048] flex items-center justify-center gap-2 disabled:opacity-60"
              >
                {creating ? (
                  <>
                    <Loader2 className="w-4 h-4 animate-spin" /> Submitting…
                  </>
                ) : (
                  "Submit Ticket"
                )}
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}