"use client";

import { useState, useEffect, use, useCallback } from "react";
import type { ReactNode } from "react";
import Link from "next/link";
import { formatDistanceToNow } from "date-fns";
import {
  ArrowLeftIcon,
  BotIcon,
  CheckCircle2Icon,
  ChevronDownIcon,
  CircleIcon,
  Clock3Icon,
  FileTextIcon,
  MessageSquareIcon,
  PaperclipIcon,
  PencilIcon,
  SaveIcon,
  SendIcon,
  UserRoundIcon,
  XIcon,
} from "lucide-react";
import {
  getTicket,
  getTicketTransactions,
  getQueues,
  getLifecycles,
  getUsers,
  getQueueCustomFields,
  previewTicket,
  updateTicket,
  updateTicketCustomField,
  sendComment,
} from "@/lib/api";
import type {
  Ticket,
  Transaction,
  Queue,
  Lifecycle,
  User,
  QueueCustomField,
  PreviewResult,
  UpdateResult,
} from "@/lib/types";
import { Separator } from "@/components/ui/separator";
import { cn, formatTicketId } from "@/lib/utils";

const STATUS_COLORS: Record<string, string> = {
  new: "#64748b",
  open: "#2563eb",
  in_progress: "#d97706",
  resolved: "#16a34a",
  closed: "#71717a",
};

const STATUS_LABELS: Record<string, string> = {
  new: "New",
  open: "Open",
  in_progress: "In progress",
  resolved: "Resolved",
  closed: "Closed",
};

const DEFAULT_STATUSES = ["new", "open", "in_progress", "resolved", "closed"];

function getInitial(name: string): string {
  if (!name) return "?";
  return name.charAt(0).toUpperCase();
}

function getInitialColor(name: string): string {
  const colors = ["#2563eb", "#0f766e", "#9333ea", "#d97706", "#16a34a"];
  let hash = 0;
  for (let i = 0; i < name.length; i++) {
    hash = name.charCodeAt(i) + ((hash << 5) - hash);
  }
  return colors[Math.abs(hash) % colors.length] ?? colors[0];
}

function statusLabel(status: string) {
  return STATUS_LABELS[status] ?? status.replaceAll("_", " ");
}

function StatusBadge({ status }: { status: string }) {
  return (
    <span className="inline-flex h-7 items-center gap-2 rounded border border-border bg-card px-2.5 text-xs font-semibold text-foreground shadow-sm">
      <span
        className="h-2 w-2 rounded-full"
        style={{ backgroundColor: STATUS_COLORS[status] ?? STATUS_COLORS.new }}
      />
      {statusLabel(status)}
    </span>
  );
}

function userLabel(users: User[], userId: string | null) {
  if (!userId) return "Unassigned";
  const user = users.find((item) => item.id === userId);
  return user?.username ?? userId;
}

function TransactionCard({
  tx,
  users,
  customFieldLabels,
}: {
  tx: Transaction;
  users: User[];
  customFieldLabels: Record<string, string>;
}) {
  const isSystem =
    tx.transaction_type === "StatusChange" ||
    tx.transaction_type === "SetOwner" ||
    tx.transaction_type === "CustomFieldChange" ||
    tx.transaction_type === "Create";
  const isInternal = tx.transaction_type === "Comment";
  const isMessage = tx.transaction_type === "Correspond" || isInternal;
  const timeAgo = formatDistanceToNow(new Date(tx.created_at), { addSuffix: true });
  const body =
    typeof tx.data === "object" && tx.data !== null && "body" in (tx.data as Record<string, unknown>)
      ? String((tx.data as Record<string, unknown>).body)
      : tx.transaction_type;

  if (isSystem) {
    let message = tx.transaction_type;
    if (tx.transaction_type === "Create") {
      message = "Ticket created";
    } else if (tx.transaction_type === "StatusChange") {
      const oldLabel = tx.old_value ? statusLabel(tx.old_value) : "?";
      const newLabel = tx.new_value ? statusLabel(tx.new_value) : "?";
      message = `Status changed from ${oldLabel} to ${newLabel}`;
    } else if (tx.transaction_type === "SetOwner") {
      message = tx.new_value ? `Assigned to ${userLabel(users, tx.new_value)}` : "Unassigned";
    } else if (tx.transaction_type === "CustomFieldChange") {
      const fieldName = tx.field ? customFieldLabels[tx.field] ?? "Custom field" : "Custom field";
      message = tx.new_value
        ? `${fieldName} set to ${tx.new_value}`
        : `${fieldName} cleared`;
    }

    return (
      <div className="grid grid-cols-[28px_minmax(0,1fr)] gap-3 px-6 py-3">
        <div className="flex justify-center">
          <span className="mt-1 flex h-5 w-5 items-center justify-center rounded bg-muted text-muted-foreground">
            <BotIcon className="h-3.5 w-3.5" />
          </span>
        </div>
        <div className="rounded-md border border-border bg-muted/55 px-3 py-2 text-sm">
          <div className="flex flex-wrap items-center gap-x-2 gap-y-1">
            <span className="font-medium text-foreground">{message}</span>
            <span className="text-xs text-muted-foreground">{timeAgo}</span>
          </div>
        </div>
      </div>
    );
  }

  return (
    <article className="grid grid-cols-[28px_minmax(0,1fr)] gap-3 px-6 py-4">
      <div
        className="flex h-7 w-7 items-center justify-center rounded-md text-[11px] font-semibold text-white"
        style={{ backgroundColor: getInitialColor(userLabel(users, tx.creator_id)) }}
      >
        {getInitial(userLabel(users, tx.creator_id))}
      </div>
      <div className="overflow-hidden rounded-md border border-border bg-card shadow-sm">
        <div className="flex flex-wrap items-center justify-between gap-2 border-b border-border bg-muted/35 px-3 py-2">
          <div className="flex items-center gap-2">
            {isMessage ? (
              <MessageSquareIcon className="h-3.5 w-3.5 text-muted-foreground" />
            ) : (
              <FileTextIcon className="h-3.5 w-3.5 text-muted-foreground" />
            )}
            <span className="text-sm font-semibold text-foreground">
              {userLabel(users, tx.creator_id)}
            </span>
            {isInternal && (
              <span className="rounded bg-amber-500/12 px-1.5 py-0.5 text-[10px] font-semibold uppercase text-amber-700 dark:text-amber-300">
                Internal
              </span>
            )}
          </div>
          <span className="text-xs text-muted-foreground">{timeAgo}</span>
        </div>
        <p className="whitespace-pre-wrap px-3 py-3 text-sm leading-6 text-foreground">
          {body}
        </p>
      </div>
    </article>
  );
}

function PropertyRow({ label, value }: { label: string; value: ReactNode }) {
  return (
    <div className="grid grid-cols-[92px_minmax(0,1fr)] gap-3 border-b border-border px-3 py-2.5 last:border-b-0">
      <dt className="text-[11px] font-semibold uppercase text-muted-foreground">{label}</dt>
      <dd className="min-w-0 truncate text-sm text-foreground">{value}</dd>
    </div>
  );
}

export default function TicketDetailPage({
  params,
}: {
  params: Promise<{ id: string }>;
}) {
  const { id: idParam } = use(params);
  const id = Number(idParam);

  const [ticket, setTicket] = useState<Ticket | null>(null);
  const [transactions, setTransactions] = useState<Transaction[]>([]);
  const [queue, setQueue] = useState<Queue | null>(null);
  const [lifecycles, setLifecycles] = useState<Lifecycle[]>([]);
  const [users, setUsers] = useState<User[]>([]);
  const [queueFields, setQueueFields] = useState<QueueCustomField[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [fieldError, setFieldError] = useState<string | null>(null);

  const [replyText, setReplyText] = useState("");
  const [replyMode, setReplyMode] = useState<"public" | "internal">("public");
  const [sending, setSending] = useState(false);
  const [sendError, setSendError] = useState<string | null>(null);

  const [statusSelectOpen, setStatusSelectOpen] = useState(false);
  const [pendingStatus, setPendingStatus] = useState<string | null>(null);
  const [preview, setPreview] = useState<PreviewResult | null>(null);
  const [previewError, setPreviewError] = useState<string | null>(null);
  const [applyLoading, setApplyLoading] = useState(false);
  const [scripResults, setScripResults] = useState<UpdateResult["scrip_results"] | null>(null);
  const [editingSubject, setEditingSubject] = useState(false);
  const [subjectDraft, setSubjectDraft] = useState("");
  const [fieldSaving, setFieldSaving] = useState<"subject" | "owner" | null>(null);
  const [customFieldDrafts, setCustomFieldDrafts] = useState<Record<string, string>>({});
  const [customFieldSaving, setCustomFieldSaving] = useState<string | null>(null);

  const fetchData = useCallback(async () => {
    setLoading(true);
    setError(null);

    const [ticketRes, txRes, queuesRes, lifecycleRes, usersRes] = await Promise.all([
      getTicket(id),
      getTicketTransactions(id),
      getQueues(),
      getLifecycles(),
      getUsers(),
    ]);

    if (ticketRes.error) {
      setError(ticketRes.error);
    } else {
      setTicket(ticketRes.data);
      setSubjectDraft(ticketRes.data?.subject ?? "");
    }

    if (txRes.error) {
      setError((prev) => prev || txRes.error);
    } else {
      setTransactions(txRes.data ?? []);
    }

    if (queuesRes.data && ticketRes.data) {
      const matchedQueue = queuesRes.data.find((item) => item.id === ticketRes.data!.queue_id);
      if (matchedQueue) setQueue(matchedQueue);
    }

    if (lifecycleRes.error) {
      setError((prev) => prev || lifecycleRes.error);
    } else {
      setLifecycles(lifecycleRes.data ?? []);
    }

    if (ticketRes.data) {
      const { data, error } = await getQueueCustomFields(ticketRes.data.queue_id);
      if (error) {
        setError((prev) => prev || error);
      } else {
        setQueueFields(data ?? []);
      }

      setCustomFieldDrafts(
        Object.fromEntries(
          (ticketRes.data.custom_fields ?? []).map((value) => [value.custom_field_id, value.value])
        )
      );
    }

    if (usersRes.error) {
      setError((prev) => prev || usersRes.error);
    } else {
      setUsers(usersRes.data ?? []);
    }

    setLoading(false);
  }, [id]);

  useEffect(() => {
    void Promise.resolve().then(() => fetchData());
  }, [fetchData]);

  const handleStatusSelect = async (newStatus: string) => {
    setPendingStatus(newStatus);
    setStatusSelectOpen(false);
    setPreview(null);
    setPreviewError(null);
    setScripResults(null);

    if (newStatus === ticket?.status) return;

    const { data, error } = await previewTicket(id, { status: newStatus });

    if (error) {
      setPreviewError(error);
      setPendingStatus(null);
    } else {
      setPreview(data);
    }
  };

  const handleApplyStatus = async () => {
    if (!pendingStatus) return;
    setApplyLoading(true);
    setPreviewError(null);

    const { data, error } = await updateTicket(id, { status: pendingStatus });

    setApplyLoading(false);

    if (error) {
      setPreviewError(error);
    } else if (data) {
      setTicket(data.ticket);
      setScripResults(data.scrip_results);
      setPreview(null);
      setPendingStatus(null);
      const txRes = await getTicketTransactions(id);
      if (txRes.data) setTransactions(txRes.data);
    }
  };

  const handleCancelStatus = () => {
    setPendingStatus(null);
    setPreview(null);
    setPreviewError(null);
    setScripResults(null);
  };

  const refreshTransactions = async () => {
    const txRes = await getTicketTransactions(id);
    if (txRes.data) setTransactions(txRes.data);
  };

  const handleSaveSubject = async () => {
    const nextSubject = subjectDraft.trim();
    if (!ticket || !nextSubject || nextSubject === ticket.subject || fieldSaving) {
      setEditingSubject(false);
      setSubjectDraft(ticket?.subject ?? "");
      return;
    }

    setFieldSaving("subject");
    setFieldError(null);

    const { data, error } = await updateTicket(id, { subject: nextSubject });

    setFieldSaving(null);

    if (error) {
      setFieldError(error);
      return;
    }

    if (data) {
      setTicket(data.ticket);
      setSubjectDraft(data.ticket.subject);
      setEditingSubject(false);
      await refreshTransactions();
    }
  };

  const handleOwnerChange = async (ownerId: string) => {
    if (!ticket || fieldSaving) return;
    const nextOwnerId = ownerId || null;
    if (nextOwnerId === ticket.owner_id) return;

    setFieldSaving("owner");
    setFieldError(null);

    const { data, error } = await updateTicket(id, { owner_id: nextOwnerId });

    setFieldSaving(null);

    if (error) {
      setFieldError(error);
      return;
    }

    if (data) {
      setTicket(data.ticket);
      await refreshTransactions();
    }
  };

  const handleCustomFieldSave = async (fieldId: string) => {
    if (!ticket || customFieldSaving) return;
    const value = customFieldDrafts[fieldId]?.trim() ?? "";
    const currentValue = ticket.custom_fields?.find((item) => item.custom_field_id === fieldId)?.value ?? "";
    if (value === currentValue) return;
    const field = queueFields.find((assignment) => assignment.custom_field_id === fieldId)?.custom_field;
    if (value && field?.pattern) {
      const regex = new RegExp(field.pattern);
      if (!regex.test(value)) {
        setFieldError(`${field.name}: value does not match the required pattern.`);
        return;
      }
    }

    setCustomFieldSaving(fieldId);
    setFieldError(null);

    const { error } = await updateTicketCustomField(id, fieldId, value);

    setCustomFieldSaving(null);

    if (error) {
      setFieldError(error);
      return;
    }

    const [ticketRes, txRes] = await Promise.all([
      getTicket(id),
      getTicketTransactions(id),
    ]);
    if (ticketRes.data) {
      setTicket(ticketRes.data);
      setCustomFieldDrafts(
        Object.fromEntries(
          (ticketRes.data.custom_fields ?? []).map((item) => [item.custom_field_id, item.value])
        )
      );
    }
    if (txRes.data) setTransactions(txRes.data);
  };

  const customFieldValue = (fieldId: string) =>
    ticket?.custom_fields?.find((item) => item.custom_field_id === fieldId)?.value ?? "";

  const handleSendComment = async () => {
    if (!replyText.trim() || sending) return;
    setSending(true);
    setSendError(null);

    const { error } = await sendComment(id, {
      body: replyText.trim(),
      internal: replyMode === "internal",
    });

    setSending(false);

    if (error) {
      setSendError(error);
    } else {
      setReplyText("");
      setSendError(null);
      const txRes = await getTicketTransactions(id);
      if (txRes.data) setTransactions(txRes.data);
    }
  };

  if (loading) {
    return (
      <div className="grid h-full grid-cols-1 xl:grid-cols-[minmax(0,1fr)_348px]">
        <div className="flex flex-col">
          <div className="border-b border-border bg-card/80 px-6 py-5">
            <div className="h-5 w-32 animate-pulse rounded bg-muted" />
            <div className="mt-3 h-8 w-2/3 animate-pulse rounded bg-muted" />
          </div>
          <div className="flex-1 space-y-3 p-6">
            {Array.from({ length: 6 }).map((_, index) => (
              <div key={index} className="grid grid-cols-[28px_minmax(0,1fr)] gap-3">
                <div className="h-7 w-7 animate-pulse rounded bg-muted" />
                <div className="h-20 animate-pulse rounded-md bg-muted" />
              </div>
            ))}
          </div>
        </div>
        <div className="hidden border-l border-border bg-card/70 p-5 xl:block">
          <div className="h-72 animate-pulse rounded-md bg-muted" />
        </div>
      </div>
    );
  }

  if (error && !ticket) {
    return (
      <div className="flex h-full flex-col items-center justify-center">
        <p className="text-sm text-destructive">{error}</p>
        <button
          onClick={fetchData}
          className="mt-2 text-sm font-medium text-primary hover:text-primary/80"
        >
          Retry
        </button>
      </div>
    );
  }

  if (!ticket) {
    return (
      <div className="flex h-full flex-col items-center justify-center">
        <p className="text-sm text-muted-foreground">Ticket not found</p>
      </div>
    );
  }

  const lifecycle = queue?.lifecycle_id
    ? lifecycles.find((item) => item.id === queue.lifecycle_id)
    : null;
  const statusOptions = lifecycle
    ? Array.from(new Set([
        ticket.status,
        ...(lifecycle.definition.transitions[ticket.status] ?? []),
        ...(lifecycle.definition.transitions["*"] ?? []),
      ]))
    : Array.from(new Set([ticket.status, ...DEFAULT_STATUSES]));
  const currentStatusColor = STATUS_COLORS[ticket.status] || STATUS_COLORS.new;
  const currentStatusLabel = statusLabel(ticket.status);
  const customFieldLabels = Object.fromEntries(
    queueFields.map((assignment) => [
      assignment.custom_field_id,
      assignment.custom_field?.name ?? assignment.custom_field_id,
    ])
  );

  return (
    <div className="grid h-full grid-cols-1 bg-background/80 xl:grid-cols-[minmax(0,1fr)_348px]">
      <main className="flex min-w-0 flex-col">
        <header className="shrink-0 border-b border-border bg-card/86 backdrop-blur">
          <div className="flex items-center justify-between gap-3 border-b border-border px-5 py-2.5">
            <Link
              href="/"
              className="inline-flex items-center gap-1.5 text-xs font-semibold text-muted-foreground transition-colors hover:text-foreground"
            >
              <ArrowLeftIcon className="h-3.5 w-3.5" />
              Work queue
            </Link>
            <div className="flex items-center gap-2 text-xs text-muted-foreground">
              <Clock3Icon className="h-3.5 w-3.5" />
              Updated {formatDistanceToNow(new Date(ticket.updated_at), { addSuffix: true })}
            </div>
          </div>

          <div className="px-5 py-4 lg:px-6">
            <div className="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
              <div className="min-w-0">
                <div className="flex flex-wrap items-center gap-2">
                  <span className="font-mono text-xs font-semibold text-muted-foreground">
                    {formatTicketId(ticket.id)}
                  </span>
                  <StatusBadge status={ticket.status} />
                  <span className="truncate text-xs font-medium text-muted-foreground">
                    {queue?.name || ticket.queue_id}
                  </span>
                </div>
                <div className="mt-2 flex max-w-4xl items-start gap-2">
                  {editingSubject ? (
                    <>
                      <textarea
                        value={subjectDraft}
                        onChange={(event) => setSubjectDraft(event.target.value)}
                        onKeyDown={(event) => {
                          if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
                            void handleSaveSubject();
                          }
                          if (event.key === "Escape") {
                            setEditingSubject(false);
                            setSubjectDraft(ticket.subject);
                          }
                        }}
                        rows={2}
                        className="min-h-20 flex-1 resize-none rounded-md border border-input bg-background px-3 py-2 text-xl font-semibold leading-tight text-foreground shadow-sm outline-none focus:border-ring"
                        autoFocus
                      />
                      <div className="flex shrink-0 items-center gap-1">
                        <button
                          onClick={() => void handleSaveSubject()}
                          disabled={!subjectDraft.trim() || fieldSaving === "subject"}
                          className="flex h-8 w-8 items-center justify-center rounded-md bg-primary text-primary-foreground transition-colors hover:bg-primary/90 disabled:bg-muted disabled:text-muted-foreground"
                          title="Save subject"
                          type="button"
                        >
                          <SaveIcon className="h-4 w-4" />
                        </button>
                        <button
                          onClick={() => {
                            setEditingSubject(false);
                            setSubjectDraft(ticket.subject);
                          }}
                          className="flex h-8 w-8 items-center justify-center rounded-md border border-border bg-card text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
                          title="Cancel"
                          type="button"
                        >
                          <XIcon className="h-4 w-4" />
                        </button>
                      </div>
                    </>
                  ) : (
                    <>
                      <h1 className="min-w-0 flex-1 text-2xl font-semibold leading-tight text-foreground">
                        {ticket.subject}
                      </h1>
                      <button
                        onClick={() => {
                          setSubjectDraft(ticket.subject);
                          setEditingSubject(true);
                        }}
                        className="mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-md border border-border bg-card text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
                        title="Edit subject"
                        type="button"
                      >
                        <PencilIcon className="h-4 w-4" />
                      </button>
                    </>
                  )}
                </div>
                {fieldError && <p className="mt-2 text-xs text-destructive">{fieldError}</p>}
              </div>
            </div>
          </div>
        </header>

        <section className="min-h-0 flex-1 overflow-y-auto bg-card/38">
          {transactions.length === 0 ? (
            <div className="flex min-h-96 flex-col items-center justify-center px-6 text-center">
              <div className="mb-3 flex h-11 w-11 items-center justify-center rounded-md border border-border bg-card">
                <MessageSquareIcon className="h-5 w-5 text-muted-foreground" />
              </div>
              <p className="text-sm font-medium text-foreground">No activity yet</p>
              <p className="mt-1 text-sm text-muted-foreground">
                Reply or change status to start the ticket ledger.
              </p>
            </div>
          ) : (
            <div className="mx-auto max-w-4xl py-4">
              {transactions.map((tx) => (
                <TransactionCard
                  key={tx.id}
                  tx={tx}
                  users={users}
                  customFieldLabels={customFieldLabels}
                />
              ))}
            </div>
          )}
        </section>

        <footer className="shrink-0 border-t border-border bg-card/90 p-4 backdrop-blur">
          <div className="mx-auto max-w-4xl rounded-md border border-border bg-background/72 p-3 shadow-sm">
            <div className="mb-2 flex items-center justify-between gap-2">
              <div className="flex rounded-md border border-border bg-muted/55 p-1">
                <button
                  onClick={() => setReplyMode("public")}
                  className={cn(
                    "h-7 rounded px-2.5 text-xs font-semibold transition-colors",
                    replyMode === "public"
                      ? "bg-card text-foreground shadow-sm"
                      : "text-muted-foreground hover:text-foreground"
                  )}
                >
                  Reply
                </button>
                <button
                  onClick={() => setReplyMode("internal")}
                  className={cn(
                    "h-7 rounded px-2.5 text-xs font-semibold transition-colors",
                    replyMode === "internal"
                      ? "bg-card text-foreground shadow-sm"
                      : "text-muted-foreground hover:text-foreground"
                  )}
                >
                  Internal note
                </button>
              </div>
              <span className="text-xs text-muted-foreground">
                {replyMode === "internal" ? "Visible to staff only" : "Public correspondence"}
              </span>
            </div>

            <div className="flex items-end gap-2">
              <textarea
                value={replyText}
                onChange={(event) => {
                  setReplyText(event.target.value);
                  setSendError(null);
                }}
                placeholder={replyMode === "internal" ? "Add internal context..." : "Write a reply..."}
                rows={3}
                className="min-h-24 flex-1 resize-none rounded-md border border-input bg-card/90 px-3 py-2 text-sm leading-6 text-foreground shadow-sm outline-none transition-colors placeholder:text-muted-foreground focus:border-ring"
              />
              <div className="flex items-center gap-1">
                <button
                  className="flex h-9 w-9 items-center justify-center rounded-md border border-border bg-card text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
                  title="Attach file (coming soon)"
                  type="button"
                >
                  <PaperclipIcon className="h-4 w-4" />
                </button>
                <button
                  onClick={handleSendComment}
                  disabled={!replyText.trim() || sending}
                  className={cn(
                    "flex h-9 w-9 items-center justify-center rounded-md transition-colors",
                    replyText.trim() && !sending
                      ? "bg-primary text-primary-foreground hover:bg-primary/90"
                      : "bg-muted text-muted-foreground"
                  )}
                  type="button"
                >
                  {sending ? (
                    <svg className="h-4 w-4 animate-spin" viewBox="0 0 24 24" fill="none">
                      <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
                      <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
                    </svg>
                  ) : (
                    <SendIcon className="h-4 w-4" />
                  )}
                </button>
              </div>
            </div>

            {sendError && <p className="mt-2 text-xs text-destructive">{sendError}</p>}
          </div>
        </footer>
      </main>

      <aside className="hidden min-h-0 overflow-y-auto border-l border-border bg-card/78 backdrop-blur xl:block">
        <div className="space-y-5 p-5">
          <section>
            <div className="mb-2 flex items-center justify-between">
              <h2 className="text-xs font-semibold uppercase text-muted-foreground">Status</h2>
              <CircleIcon
                className="h-3.5 w-3.5"
                style={{ color: currentStatusColor }}
              />
            </div>
            <div className="relative">
              <button
                onClick={() => setStatusSelectOpen(!statusSelectOpen)}
                className="flex w-full items-center gap-3 rounded-md border border-border bg-background/70 px-3 py-2.5 text-sm shadow-sm transition-colors hover:bg-accent"
                type="button"
              >
                <span
                  className="h-3 w-3 rounded-full"
                  style={{ backgroundColor: currentStatusColor }}
                />
                <span className="flex-1 text-left font-semibold text-foreground">
                  {currentStatusLabel}
                </span>
                <ChevronDownIcon className="h-4 w-4 text-muted-foreground" />
              </button>

              {statusSelectOpen && (
                <div className="absolute left-0 right-0 top-full z-20 mt-1 overflow-hidden rounded-md border border-border bg-popover shadow-xl">
                  {statusOptions.map((status) => {
                    const isCurrent = status === ticket.status;
                    return (
                      <button
                        key={status}
                        onClick={() => handleStatusSelect(status)}
                        disabled={isCurrent}
                        className={cn(
                          "flex w-full items-center gap-3 px-3 py-2.5 text-left text-sm transition-colors",
                          isCurrent
                            ? "bg-accent text-muted-foreground"
                            : "text-foreground hover:bg-accent"
                        )}
                        type="button"
                      >
                        <span
                          className="h-3 w-3 rounded-full"
                          style={{ backgroundColor: STATUS_COLORS[status] ?? STATUS_COLORS.new }}
                        />
                        {statusLabel(status)}
                        {isCurrent && <span className="ml-auto text-xs">current</span>}
                      </button>
                    );
                  })}
                </div>
              )}
            </div>
          </section>

          {preview && (
            <section className="rounded-md border border-border bg-background/70 p-3 shadow-sm">
              <div className="mb-2 flex items-center gap-2 text-sm font-semibold text-foreground">
                <BotIcon className="h-4 w-4 text-primary" />
                Automation preview
              </div>
              <p className="text-xs text-muted-foreground">
                Changing to{" "}
                <span className="font-semibold text-foreground">
                  {pendingStatus ? statusLabel(pendingStatus) : ""}
                </span>
              </p>
              <div className="my-3 space-y-1.5">
                {preview.prepared_scrips.length > 0 ? (
                  preview.prepared_scrips.map((scrip) => (
                    <div
                      key={scrip.scripId}
                      className="flex items-center gap-2 rounded border border-border bg-card px-2 py-1.5 text-xs text-foreground"
                    >
                      <span className="h-1.5 w-1.5 rounded-full bg-primary" />
                      {scrip.scripName}
                    </div>
                  ))
                ) : (
                  <p className="rounded border border-border bg-muted/40 px-2 py-1.5 text-xs text-muted-foreground">
                    No scrips will fire
                  </p>
                )}
              </div>
              <div className="flex items-center gap-2">
                <button
                  onClick={handleApplyStatus}
                  disabled={applyLoading}
                  className="rounded-md bg-primary px-2.5 py-1.5 text-xs font-semibold text-primary-foreground transition-colors hover:bg-primary/90 disabled:opacity-50"
                  type="button"
                >
                  {applyLoading ? "Applying..." : "Apply change"}
                </button>
                <button
                  onClick={handleCancelStatus}
                  disabled={applyLoading}
                  className="rounded-md px-2.5 py-1.5 text-xs font-semibold text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
                  type="button"
                >
                  Cancel
                </button>
              </div>
            </section>
          )}

          {previewError && (
            <div className="rounded-md border border-destructive/20 bg-destructive/10 p-3">
              <p className="text-xs text-destructive">{previewError}</p>
            </div>
          )}

          {scripResults && (
            <section className="rounded-md border border-border bg-background/70 p-3 shadow-sm">
              <div className="mb-2 flex items-center gap-2 text-sm font-semibold text-foreground">
                <CheckCircle2Icon className="h-4 w-4 text-emerald-600" />
                Scrip results
              </div>
              <div className="space-y-1.5">
                {scripResults.map((result) => (
                  <div
                    key={result.scripId}
                    className={cn(
                      "flex items-center gap-2 text-xs",
                      result.success ? "text-emerald-700 dark:text-emerald-300" : "text-destructive"
                    )}
                  >
                    <span
                      className={cn(
                        "h-1.5 w-1.5 rounded-full",
                        result.success ? "bg-emerald-600" : "bg-destructive"
                      )}
                    />
                    {result.message}
                  </div>
                ))}
              </div>
              <button
                onClick={() => setScripResults(null)}
                className="mt-2 text-xs font-medium text-muted-foreground hover:text-foreground"
                type="button"
              >
                Dismiss
              </button>
            </section>
          )}

          <Separator />

          <section>
            <h2 className="mb-2 text-xs font-semibold uppercase text-muted-foreground">
              Assignment
            </h2>
            <dl className="overflow-hidden rounded-md border border-border bg-background/60">
              <div className="grid grid-cols-[92px_minmax(0,1fr)] gap-3 border-b border-border px-3 py-2.5">
                <dt className="text-[11px] font-semibold uppercase text-muted-foreground">Owner</dt>
                <dd className="min-w-0">
                  <select
                    value={ticket.owner_id ?? ""}
                    onChange={(event) => void handleOwnerChange(event.target.value)}
                    disabled={fieldSaving === "owner"}
                    className="h-8 w-full rounded-md border border-input bg-card px-2 text-sm text-foreground outline-none transition-colors focus:border-ring disabled:opacity-60"
                    aria-label="Owner"
                  >
                    <option value="">Unassigned</option>
                    {users.map((user) => (
                      <option key={user.id} value={user.id}>
                        {user.username}
                      </option>
                    ))}
                  </select>
                </dd>
              </div>
              <PropertyRow label="Priority" value="Not set" />
            </dl>
          </section>

          <section>
            <h2 className="mb-2 text-xs font-semibold uppercase text-muted-foreground">
              Details
            </h2>
            <dl className="overflow-hidden rounded-md border border-border bg-background/60">
              <PropertyRow label="Queue" value={queue?.name || ticket.queue_id} />
              <PropertyRow
                label="Created"
                value={formatDistanceToNow(new Date(ticket.created_at), { addSuffix: true })}
              />
              <PropertyRow
                label="Updated"
                value={formatDistanceToNow(new Date(ticket.updated_at), { addSuffix: true })}
              />
              {ticket.resolved_at && (
                <PropertyRow
                  label="Resolved"
                  value={formatDistanceToNow(new Date(ticket.resolved_at), { addSuffix: true })}
                />
              )}
            </dl>
          </section>

          <section>
            <h2 className="mb-2 text-xs font-semibold uppercase text-muted-foreground">
              Custom fields
            </h2>
            {queueFields.length === 0 ? (
              <div className="rounded-md border border-border bg-background/60 px-3 py-3 text-sm text-muted-foreground">
                No fields are assigned to this queue.
              </div>
            ) : (
              <div className="overflow-hidden rounded-md border border-border bg-background/60">
                {queueFields.map((assignment) => {
                  const field = assignment.custom_field;
                  const fieldId = assignment.custom_field_id;
                  const options = Array.isArray(field?.values)
                    ? field.values.map((value) => String(value))
                    : [];
                  const fieldType = field?.field_type.toLowerCase() ?? "";
                  const currentDraft = customFieldDrafts[fieldId] ?? customFieldValue(fieldId);
                  const dirty = currentDraft !== customFieldValue(fieldId);
                  const isSaving = customFieldSaving === fieldId;

                  return (
                    <div
                      key={assignment.id}
                      className="grid gap-2 border-b border-border px-3 py-3 last:border-b-0"
                    >
                      <label className="text-[11px] font-semibold uppercase text-muted-foreground">
                        {field?.name ?? fieldId}
                      </label>
                      <div className="flex items-center gap-2">
                        {(fieldType.includes("select") || options.length > 0) && options.length > 0 ? (
                          <select
                            value={currentDraft}
                            onChange={(event) => {
                              const nextValue = event.target.value;
                              setCustomFieldDrafts((current) => ({ ...current, [fieldId]: nextValue }));
                            }}
                            className="h-8 min-w-0 flex-1 rounded-md border border-input bg-card px-2 text-sm text-foreground outline-none transition-colors focus:border-ring"
                          >
                            <option value="">Not set</option>
                            {options.map((option) => (
                              <option key={option} value={option}>
                                {option}
                              </option>
                            ))}
                          </select>
                        ) : (
                          <input
                            value={currentDraft}
                            onChange={(event) =>
                              setCustomFieldDrafts((current) => ({ ...current, [fieldId]: event.target.value }))
                            }
                            onKeyDown={(event) => {
                              if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
                                void handleCustomFieldSave(fieldId);
                              }
                            }}
                            placeholder={field?.pattern ? field.pattern : "Not set"}
                            className="h-8 min-w-0 flex-1 rounded-md border border-input bg-card px-2 text-sm text-foreground outline-none transition-colors placeholder:text-muted-foreground focus:border-ring"
                          />
                        )}
                        <button
                          onClick={() => void handleCustomFieldSave(fieldId)}
                          disabled={!dirty || isSaving}
                          className={cn(
                            "flex h-8 w-8 shrink-0 items-center justify-center rounded-md transition-colors",
                            dirty && !isSaving
                              ? "bg-primary text-primary-foreground hover:bg-primary/90"
                              : "border border-border bg-card text-muted-foreground"
                          )}
                          title="Save custom field"
                          type="button"
                        >
                          <SaveIcon className="h-4 w-4" />
                        </button>
                      </div>
                    </div>
                  );
                })}
              </div>
            )}
          </section>

          <section className="rounded-md border border-border bg-accent/38 p-3">
            <div className="flex items-center gap-2 text-sm font-semibold text-foreground">
              <UserRoundIcon className="h-4 w-4 text-primary" />
              Work mode
            </div>
            <p className="mt-2 text-sm text-muted-foreground">
              Reply from the dock, preview status automation, then commit changes when the side effects look right.
            </p>
          </section>
        </div>
      </aside>
    </div>
  );
}
