"use client";

import { Suspense, useCallback, useEffect, useMemo, useState } from "react";
import { createPortal } from "react-dom";
import { useRouter, useSearchParams } from "next/navigation";
import {
  ArrowDownAZIcon,
  CheckCircle2Icon,
  ChevronRightIcon,
  GaugeIcon,
  LayoutGridIcon,
  LayoutListIcon,
  PlusIcon,
  RefreshCwIcon,
  SaveIcon,
  SearchIcon,
  SlidersHorizontalIcon,
  XIcon,
} from "lucide-react";
import { formatDistanceToNow } from "date-fns";
import { createTicket, getCustomFields, getLifecycles, getQueueCustomFields, getQueues, getTickets, getUsers, getViews, createView, deleteView, getDashboards, getTicketTransactions, updateTicket } from "@/lib/api";
import type { CustomField, Lifecycle, Queue, QueueCustomField, SavedView, Ticket, Transaction, User } from "@/lib/types";
import { Button } from "@/components/ui/button";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { cn, formatTicketId } from "@/lib/utils";

const STATUS_META: Record<string, { label: string; color: string; tone: string }> = {
  new: { label: "New", color: "#64748b", tone: "bg-slate-500/10 text-slate-700 dark:text-slate-300" },
  open: { label: "Open", color: "#2563eb", tone: "bg-blue-500/10 text-blue-700 dark:text-blue-300" },
  in_progress: { label: "In progress", color: "#d97706", tone: "bg-amber-500/10 text-amber-700 dark:text-amber-300" },
  resolved: { label: "Resolved", color: "#16a34a", tone: "bg-emerald-500/10 text-emerald-700 dark:text-emerald-300" },
  closed: { label: "Closed", color: "#71717a", tone: "bg-zinc-500/10 text-zinc-700 dark:text-zinc-300" },
};

const VIEW_LABELS: Record<string, string> = {
  my: "My tickets",
  unassigned: "Unassigned",
  recent: "Recently updated",
};

type Density = "comfortable" | "compact";
type SortKey = "updated" | "created" | "id";

interface ColumnConfig {
  key: string;
  label: string;
  width: number;  // px
  visible: boolean;
}

const ALL_COLUMNS: ColumnConfig[] = [
  { key: "id", label: "ID", width: 100, visible: true },
  { key: "subject", label: "Subject", width: 320, visible: true },
  { key: "status", label: "Status", width: 120, visible: true },
  { key: "queue", label: "Queue", width: 140, visible: true },
  { key: "owner", label: "Owner", width: 130, visible: true },
  { key: "created", label: "Created", width: 130, visible: false },
  { key: "updated", label: "Updated", width: 130, visible: false },
];

function baseColumns(): ColumnConfig[] {
  return [
    { key: "id", label: "ID", width: 100, visible: true },
    { key: "subject", label: "Subject", width: 400, visible: true },
    { key: "status", label: "Status", width: 120, visible: true },
    { key: "queue", label: "Queue", width: 140, visible: true },
    { key: "owner", label: "Owner", width: 130, visible: true },
    { key: "created", label: "Created", width: 130, visible: false },
    { key: "updated", label: "Updated", width: 130, visible: false },
  ];
}

function defaultColumns(): ColumnConfig[] {
  return baseColumns().map((c) => ({ ...c }));
}

const LS_KEY = "tessera_columns";

interface Filter {
  id: string;
  field: string;       // "status" | "queue" | "owner" | custom field key ("cf.<key>")
  operator: string;    // "is" | "is_not"
  value: string;
  label: string;       // human-readable label for the chip
}

function buildFilterLabel(field: string, operator: string, valueLabel: string): string {
  const fieldLabel = field.startsWith("cf.") ? field.slice(3) : field;
  const op = operator === "is_not" ? "is not" : "is";
  return `${fieldLabel} ${op} ${valueLabel}`;
}

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

function queueName(queues: Queue[], queueId: string) {
  return queues.find((queue) => queue.id === queueId)?.name ?? queueId.slice(0, 8);
}

function relativeTime(value: string) {
  return formatDistanceToNow(new Date(value), { addSuffix: true });
}

function TicketStatusBadge({ status }: { status: string }) {
  const meta = STATUS_META[status];
  return (
    <span
      className={cn(
        "inline-flex h-6 items-center gap-1.5 rounded px-2 text-xs font-semibold capitalize",
        meta?.tone ?? "bg-muted text-muted-foreground"
      )}
    >
      <span
        className="h-1.5 w-1.5 rounded-full"
        style={{ backgroundColor: meta?.color ?? "#71717a" }}
      />
      {statusLabel(status)}
    </span>
  );
}

function StatPill({
  label,
  value,
}: {
  label: string;
  value: number;
}) {
  return (
    <span className="inline-flex h-6 items-center gap-1.5 rounded border border-border/80 bg-card/80 px-2 text-[11px] text-muted-foreground shadow-sm">
      <span className="font-semibold tabular-nums text-foreground">{value}</span>
      {label}
    </span>
  );
}

function SkeletonWorkbench() {
  return (
    <div className="flex h-full flex-col">
      <div className="border-b border-border px-5 py-4">
        <div className="h-7 w-48 animate-pulse rounded bg-muted" />
        <div className="mt-3 h-9 w-full max-w-xl animate-pulse rounded bg-muted" />
      </div>
      <div className="grid flex-1 grid-cols-1 overflow-hidden xl:grid-cols-[minmax(0,1fr)_360px]">
        <div className="overflow-hidden">
          {Array.from({ length: 12 }).map((_, index) => (
            <div key={index} className="flex items-center gap-4 border-b border-border px-5 py-4">
              <div className="h-4 w-4 animate-pulse rounded bg-muted" />
              <div className="min-w-0 flex-1 space-y-2">
                <div className="h-4 w-2/5 animate-pulse rounded bg-muted" />
                <div className="h-3 w-3/5 animate-pulse rounded bg-muted" />
              </div>
              <div className="h-6 w-20 animate-pulse rounded bg-muted" />
            </div>
          ))}
        </div>
        <div className="hidden border-l border-border p-5 xl:block">
          <div className="h-40 animate-pulse rounded-md bg-muted" />
        </div>
      </div>
    </div>
  );
}

function TicketWorkbenchContent() {
  const router = useRouter();
  const searchParams = useSearchParams();

  const [tickets, setTickets] = useState<Ticket[]>([]);
  const [queues, setQueues] = useState<Queue[]>([]);
  const [lifecycles, setLifecycles] = useState<Lifecycle[]>([]);
  const [users, setUsers] = useState<User[]>([]);
  const [customFields, setCustomFields] = useState<CustomField[]>([]);
  const [clock, setClock] = useState(0);
  const [loading, setLoading] = useState(true);
  const [refreshing, setRefreshing] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [selectedId, setSelectedId] = useState<number | null>(null);
  const [selectedTxs, setSelectedTxs] = useState<Transaction[]>([]);
  const [batchIds, setBatchIds] = useState<Set<number>>(new Set());
  const [batchSaving, setBatchSaving] = useState(false);

  const [searchQuery, setSearchQuery] = useState("");
  const [filters, setFilters] = useState<Filter[]>([]);
  const [columns, setColumns] = useState<ColumnConfig[]>(() => {
    if (typeof window === "undefined") return defaultColumns();
    try {
      const stored = localStorage.getItem(LS_KEY);
      if (stored) return JSON.parse(stored) as ColumnConfig[];
    } catch { /* ignore */ }
    return defaultColumns();
  });
  const [density, setDensity] = useState<Density>("comfortable");
  const [sortKey, setSortKey] = useState<SortKey>("updated");
  const [resizingCol, setResizingCol] = useState<string | null>(null);
  const [colPickerOpen, setColPickerOpen] = useState(false);

  // Persist columns to localStorage
  useEffect(() => {
    try { localStorage.setItem(LS_KEY, JSON.stringify(columns)); } catch { /* ignore */ }
  }, [columns]);

  // Build available columns: base + custom fields
  const availableColumns = useMemo(() => {
    const base = baseColumns();
    const cfCols: ColumnConfig[] = customFields
      .filter((cf) => cf.key)
      .map((cf) => ({
        key: `cf.${cf.key}`,
        label: cf.name,
        width: 140,
        visible: columns.find((c) => c.key === `cf.${cf.key}`)?.visible ?? false,
      }));
    // Merge with current visibility state
    const merged = base.map((bc) => {
      const current = columns.find((c) => c.key === bc.key);
      return current ?? bc;
    });
    for (const cf of cfCols) {
      const current = columns.find((c) => c.key === cf.key);
      merged.push(current ?? cf);
    }
    return merged;
  }, [customFields, columns]);

  // Saved views
  const [savedViewsList, setSavedViewsList] = useState<SavedView[]>([]);
  const [viewIdFromUrl, setViewIdFromUrl] = useState<string | null>(null);
  const [saveViewOpen, setSaveViewOpen] = useState(false);
  const [saveViewName, setSaveViewName] = useState("");
  const [addFilterOpen, setAddFilterOpen] = useState(false);
  const [addFilterField, setAddFilterField] = useState<string | null>(null); // which field type is selected
  const [addFilterOperator, setAddFilterOperator] = useState("is");
  const [addFilterValue, setAddFilterValue] = useState("");

  const [dialogOpen, setDialogOpen] = useState(false);
  const [newSubject, setNewSubject] = useState("");
  const [newQueueId, setNewQueueId] = useState("");
  const [newDescription, setNewDescription] = useState("");
  const [newQueueFields, setNewQueueFields] = useState<QueueCustomField[]>([]);
  const [newCustomFieldValues, setNewCustomFieldValues] = useState<Record<string, string>>({});
  const [newFieldsLoading, setNewFieldsLoading] = useState(false);
  const [submitting, setSubmitting] = useState(false);
  const [createError, setCreateError] = useState<string | null>(null);

  const view = searchParams.get("view") ?? "all";
  const routeQueue = searchParams.get("queue") ?? "";

  const fetchData = useCallback(
    async (background = false) => {
      if (background) {
        setRefreshing(true);
      } else {
        setLoading(true);
      }
      setError(null);
      const fetchedAt = Date.now();

      const activeQueue = routeQueue;
      const apiStatus = filters.find((f) => f.field === "status")?.value;
      const apiOwner = filters.find((f) => f.field === "owner")?.value;
      const apiQueue = filters.find((f) => f.field === "queue")?.value;
      const customFieldFilters: Record<string, string> = {};
      for (const f of filters) {
        if (f.field.startsWith("cf.")) {
          customFieldFilters[f.field.slice(3)] = f.value;
        }
      }

      const routeTeamId = searchParams.get("team_id") ?? "";
      const [ticketsRes, queuesRes, usersRes, fieldsRes, lifecycleRes] = await Promise.all([
        getTickets({
          q: searchQuery.trim() || undefined,
          status: apiStatus || undefined,
          queue_id: activeQueue || apiQueue || undefined,
          owner_id: apiOwner || undefined,
          team_id: routeTeamId || undefined,
          custom_fields: Object.keys(customFieldFilters).length > 0 ? customFieldFilters : undefined,
        }),
        getQueues(),
        getUsers(),
        getCustomFields(),
        getLifecycles(),
      ]);

      if (ticketsRes.error) {
        setError(ticketsRes.error);
        setTickets([]);
      } else {
        setTickets(ticketsRes.data ?? []);
      }

      if (queuesRes.error) {
        setError((current) => current ?? queuesRes.error);
      } else {
        const queueData = queuesRes.data ?? [];
        setQueues(queueData);
        if (!newQueueId && queueData.length > 0) {
          setNewQueueId(queueData[0].id);
        }
      }

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

      if (fieldsRes.error) {
        setError((current) => current ?? fieldsRes.error);
      } else {
        setCustomFields(fieldsRes.data ?? []);
      }

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

      setLoading(false);
      setRefreshing(false);
      setClock(fetchedAt);
    },
    [filters, newQueueId, routeQueue, searchQuery]
  );

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

  // Redirect to default dashboard if one exists and no params set
  useEffect(() => {
    if (searchParams.toString()) return;
    getDashboards().then(({ data }) => {
      const def = data?.find((d) => d.is_default);
      if (def) router.replace(`/dashboards/${def.id}`);
    });
  }, [searchParams]);

  useEffect(() => {
    if (searchParams.get("new") === "true") {
      queueMicrotask(() => setDialogOpen(true));
      const url = new URL(window.location.href);
      url.searchParams.delete("new");
      window.history.replaceState({}, "", url.toString());
    }
  }, [searchParams]);

  useEffect(() => {
    if (!newQueueId) {
      queueMicrotask(() => {
        setNewQueueFields([]);
        setNewCustomFieldValues({});
      });
      return;
    }

    let cancelled = false;
    queueMicrotask(() => {
      if (!cancelled) setNewFieldsLoading(true);
    });
    void getQueueCustomFields(newQueueId).then(({ data, error }) => {
      if (cancelled) return;
      setNewFieldsLoading(false);
      if (error) {
        setCreateError(error);
        setNewQueueFields([]);
        setNewCustomFieldValues({});
        return;
      }
      const assignments = data ?? [];
      setNewQueueFields(assignments);
      setNewCustomFieldValues((current) => {
        const next: Record<string, string> = {};
        for (const assignment of assignments) {
          next[assignment.custom_field_id] = current[assignment.custom_field_id] ?? "";
        }
        return next;
      });
    });

    return () => {
      cancelled = true;
    };
  }, [newQueueId]);

  // Load saved views list
  useEffect(() => {
    getViews().then(({ data }) => {
      if (data) setSavedViewsList(data);
    });
  }, [clock]);

  // Load view from URL param
  useEffect(() => {
    const paramViewId = searchParams.get("view_id");
    setViewIdFromUrl(paramViewId);
    if (paramViewId) {
      getViews().then(({ data }) => {
        const view = data?.find((v) => v.id === paramViewId);
        if (view?.filters && Array.isArray(view.filters)) {
          setSearchQuery("");
          setFilters(
            (view.filters as { field: string; operator: string; value: string }[])
              .filter((f) => f.field && f.value)
              .map((f) => ({
                id: crypto.randomUUID(),
                field: f.field,
                operator: f.operator || "is",
                value: f.value,
                label: buildFilterLabel(f.field, f.operator || "is", f.value),
              }))
          );
          if (view.sort_key) setSortKey(view.sort_key as SortKey);
          if (view.columns && Array.isArray(view.columns) && view.columns.length > 0) {
            setColumns(view.columns as ColumnConfig[]);
          }
        }
      });
    } else if (!paramViewId && viewIdFromUrl) {
      // User navigated away from a view — clear filters and reset columns
      setFilters([]);
      setSearchQuery("");
      setColumns(defaultColumns());
    }
  }, [searchParams]);

  const statusOptions = useMemo(() => {
    const queueFilterValue = filters.find((f) => f.field === "queue")?.value;
    const selectedFilterQueueId = routeQueue || queueFilterValue || "";
    const selectedFilterQueue = selectedFilterQueueId
      ? queues.find((queue) => queue.id === selectedFilterQueueId)
      : null;
    const selectedFilterLifecycle = selectedFilterQueue?.lifecycle_id
      ? lifecycles.find((lifecycle) => lifecycle.id === selectedFilterQueue.lifecycle_id)
      : null;
    const lifecycleStatuses = selectedFilterLifecycle
      ? [
          ...selectedFilterLifecycle.definition.statuses.initial,
          ...selectedFilterLifecycle.definition.statuses.active,
          ...selectedFilterLifecycle.definition.statuses.inactive,
        ]
      : lifecycles.flatMap((lifecycle) => [
          ...lifecycle.definition.statuses.initial,
          ...lifecycle.definition.statuses.active,
          ...lifecycle.definition.statuses.inactive,
        ]);

    return [
      { key: "all", label: "All" },
      ...Array.from(new Set([...lifecycleStatuses, ...tickets.map((ticket) => ticket.status)]))
        .filter(Boolean)
        .map((status) => ({ key: status, label: statusLabel(status) })),
    ];
  }, [filters, lifecycles, queues, routeQueue, tickets]);

  const inactiveStatuses = useMemo(
    () => new Set(
      lifecycles.length > 0
        ? lifecycles.flatMap((lifecycle) => lifecycle.definition.statuses.inactive)
        : ["resolved", "closed"]
    ),
    [lifecycles]
  );

  const metrics = useMemo(() => {
    const now = clock || 0;
    const day = 24 * 60 * 60 * 1000;
    return {
      total: tickets.length,
      active: tickets.filter((ticket) => !inactiveStatuses.has(ticket.status)).length,
      unassigned: tickets.filter((ticket) => !ticket.owner_id).length,
      stale: tickets.filter((ticket) => now && now - new Date(ticket.updated_at).getTime() > 3 * day).length,
      recent: tickets.filter((ticket) => now && now - new Date(ticket.updated_at).getTime() < day).length,
    };
  }, [clock, inactiveStatuses, tickets]);

  const filteredTickets = useMemo(() => {
    const query = searchQuery.trim().toLowerCase();
    const now = clock || 0;
    const queue = routeQueue;
    const statusFilterValue = filters.find((f) => f.field === "status")?.value;
    const queueFilterValue = filters.find((f) => f.field === "queue")?.value;

    return tickets
      .filter((ticket) => {
        if (view === "my") {
          const myOwner = searchParams.get("owner");
          if (myOwner && ticket.owner_id !== myOwner) return false;
          if (!myOwner && !ticket.owner_id) return false;
        }
        if (view === "unassigned" && ticket.owner_id) return false;
        if (view === "recent") {
          const week = 7 * 24 * 60 * 60 * 1000;
          if (!now || now - new Date(ticket.updated_at).getTime() > week) return false;
        }
        if (statusFilterValue && ticket.status !== statusFilterValue) return false;
        if (queueFilterValue && ticket.queue_id !== queueFilterValue) return false;
        if (queue && ticket.queue_id !== queue) return false;
        if (!query) return true;
        return (
          ticket.subject.toLowerCase().includes(query) ||
          formatTicketId(ticket.id).toLowerCase().includes(query) ||
          statusLabel(ticket.status).toLowerCase().includes(query) ||
          queueName(queues, ticket.queue_id).toLowerCase().includes(query)
        );
      })
      .sort((a, b) => {
        if (sortKey === "id") return b.id - a.id;
        const aDate = sortKey === "created" ? a.created_at : a.updated_at;
        const bDate = sortKey === "created" ? b.created_at : b.updated_at;
        return new Date(bDate).getTime() - new Date(aDate).getTime();
      });
  }, [clock, filters, queues, routeQueue, searchQuery, sortKey, tickets, view]);

  const selectedTicket =
    filteredTickets.find((ticket) => ticket.id === selectedId) ?? null;

  // Fetch transactions when selection changes
  useEffect(() => {
    if (!selectedTicket) { setSelectedTxs([]); return; }
    getTicketTransactions(selectedTicket.id).then(({ data }) => setSelectedTxs(data ?? []));
  }, [selectedTicket?.id]);

  const handleQuickStatus = async (ticketId: number, newStatus: string) => {
    const { data } = await updateTicket(ticketId, { status: newStatus });
    if (data) {
      setTickets((prev) => prev.map((t) => (t.id === ticketId ? data.ticket : t)));
      getTicketTransactions(ticketId).then(({ data: txs }) => setSelectedTxs(txs ?? []));
    }
  };

  const handleQuickAssign = async (ticketId: number) => {
    const { data } = await updateTicket(ticketId, { owner_id: users[0]?.id ?? null });
    if (data) {
      setTickets((prev) => prev.map((t) => (t.id === ticketId ? data.ticket : t)));
    }
  };

  const handleBatchStatus = async (newStatus: string) => {
    setBatchSaving(true);
    for (const id of batchIds) {
      await updateTicket(id, { status: newStatus });
    }
    setBatchSaving(false);
    setBatchIds(new Set());
    await fetchData();
  };

  const handleBatchAssign = async () => {
    const me = users[0]?.id;
    if (!me) return;
    setBatchSaving(true);
    for (const id of batchIds) {
      await updateTicket(id, { owner_id: me });
    }
    setBatchSaving(false);
    setBatchIds(new Set());
    await fetchData();
  };

  const toggleBatchId = (id: number) => {
    setBatchIds((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id); else next.add(id);
      return next;
    });
  };
  const handleColumnResize = (leftKey: string, rightKey: string | null, e: React.MouseEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setResizingCol(leftKey);
    const startX = e.clientX;
    const leftCol = columns.find((c) => c.key === leftKey);
    const rightCol = rightKey ? columns.find((c) => c.key === rightKey) : null;
    const leftStart = leftCol?.width ?? 140;
    const rightStart = rightCol?.width ?? 140;

    const onMove = (ev: MouseEvent) => {
      const delta = ev.clientX - startX;
      const newLeft = Math.max(50, Math.min(800, leftStart + delta));
      const newRight = rightCol ? Math.max(50, Math.min(800, rightStart - delta)) : undefined;
      setColumns((prev) =>
        prev.map((c) => {
          if (c.key === leftKey) return { ...c, width: newLeft };
          if (rightCol && c.key === rightCol.key) return { ...c, width: newRight! };
          return c;
        })
      );
    };
    const onUp = () => {
      document.removeEventListener("mousemove", onMove);
      document.removeEventListener("mouseup", onUp);
      document.body.classList.remove("select-none");
      setResizingCol(null);
    };
    document.body.classList.add("select-none");
    document.addEventListener("mousemove", onMove);
    document.addEventListener("mouseup", onUp);
  };

  const visibleTitle = routeQueue
    ? queueName(queues, routeQueue)
    : VIEW_LABELS[view] ?? "All tickets";
  const newTicketFields = newQueueFields
    .map((assignment) => assignment.custom_field)
    .filter((field): field is CustomField => Boolean(field));
  const selectedNewQueue = queues.find((queue) => queue.id === newQueueId);
  const selectedNewLifecycle = selectedNewQueue?.lifecycle_id
    ? lifecycles.find((lifecycle) => lifecycle.id === selectedNewQueue.lifecycle_id)
    : null;
  const newTicketInitialStatus = selectedNewLifecycle?.definition.statuses.initial[0] ?? "new";
  const hasQueryFilters = searchQuery.trim() || filters.length > 0;

  const clearQueryFilters = () => {
    setSearchQuery("");
    setFilters([]);
    if (routeQueue) router.push("/");
  };

  const handleCreate = async () => {
    if (!newSubject.trim() || !newQueueId) return;
    for (const field of newTicketFields) {
      const value = (newCustomFieldValues[field.id] ?? "").trim();
      if (value && field.pattern) {
        const regex = new RegExp(field.pattern);
        if (!regex.test(value)) {
          setCreateError(`${field.name}: value does not match the required pattern.`);
          return;
        }
      }
    }
    setSubmitting(true);
    setCreateError(null);

    const { data, error } = await createTicket({
      subject: newSubject.trim(),
      queue_id: newQueueId,
      description: newDescription.trim() || undefined,
      custom_fields: Object.fromEntries(
        Object.entries(newCustomFieldValues)
          .map(([fieldId, value]) => [fieldId, value.trim()])
          .filter(([, value]) => value)
      ),
    });

    setSubmitting(false);

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

    setDialogOpen(false);
    setNewSubject("");
    setNewDescription("");
    setNewCustomFieldValues({});
    if (data) router.push(`/tickets/${data.ticket.id}`);
  };

  if (loading) return <SkeletonWorkbench />;

  return (
    <div className="flex h-full flex-col bg-background/80">
      <header className="shrink-0 border-b border-border bg-card/82 backdrop-blur">
        <div className="flex flex-col gap-3 px-5 py-4 lg:px-6">
          <div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
            <div className="min-w-0">
              <div className="flex items-center gap-2 text-[11px] font-semibold uppercase text-muted-foreground">
                <GaugeIcon className="h-3.5 w-3.5" />
                Work queue
              </div>
              <h1 className="mt-1 truncate text-2xl font-semibold text-foreground">
                {visibleTitle}
              </h1>
            </div>
            <div className="flex flex-wrap items-center gap-2">
              <Button
                variant="outline"
                size="sm"
                onClick={() => fetchData(true)}
                disabled={refreshing}
                className="h-8 border-border/80 bg-card/70"
              >
                <RefreshCwIcon className={cn("h-4 w-4", refreshing && "animate-spin")} />
                Refresh
              </Button>
              {filters.length > 0 && (
                <Button
                  size="sm"
                  variant="outline"
                  onClick={() => {
                    setSaveViewName("");
                    setSaveViewOpen(true);
                  }}
                  className="h-8 border-border/80 bg-card/70"
                >
                  <SaveIcon className="h-4 w-4" />
                  Save view
                </Button>
              )}
              <Button size="sm" onClick={() => setDialogOpen(true)} className="h-8 bg-primary shadow-sm">
                <PlusIcon className="h-4 w-4" />
                New ticket
              </Button>
            </div>
          </div>

          <div className="flex flex-wrap items-center gap-2">
            <StatPill label="total" value={metrics.total} />
            <StatPill label="active" value={metrics.active} />
            <StatPill label="unassigned" value={metrics.unassigned} />
            <StatPill label="updated today" value={metrics.recent} />
            <StatPill label="needs review" value={metrics.stale} />
          </div>

          <div className="flex flex-col gap-2">
            {/* Row 1: search + sort/density */}
            <div className="flex items-center gap-2">
              <div className="relative flex-1">
                <SearchIcon className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
                <input
                  value={searchQuery}
                  onChange={(event) => setSearchQuery(event.target.value)}
                  placeholder="Search subject, ticket ID, queue, or status"
                  className="h-9 w-full rounded-md border border-input bg-card/90 pl-9 pr-3 text-sm shadow-sm outline-none transition-colors placeholder:text-muted-foreground focus:border-ring"
                />
              </div>
              {hasQueryFilters && (
                <Button
                  type="button"
                  variant="outline"
                  size="sm"
                  onClick={clearQueryFilters}
                  className="h-9 shrink-0 border-border/80 bg-card/70"
                >
                  Clear
                </Button>
              )}
              <button
                type="button"
                onClick={() => setSortKey(sortKey === "updated" ? "created" : sortKey === "created" ? "id" : "updated")}
                className="inline-flex h-9 items-center gap-2 rounded-md border border-border bg-card/90 px-3 text-sm text-muted-foreground shadow-sm transition-colors hover:bg-accent hover:text-foreground shrink-0"
                title="Change sort"
              >
                <ArrowDownAZIcon className="h-4 w-4" />
                {sortKey === "updated" ? "Updated" : sortKey === "created" ? "Created" : "ID"}
              </button>
              <button
                type="button"
                onClick={() => setDensity(density === "comfortable" ? "compact" : "comfortable")}
                className="inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md border border-border bg-card/90 text-muted-foreground shadow-sm transition-colors hover:bg-accent hover:text-foreground"
                title="Toggle density"
              >
                {density === "comfortable" ? (
                  <LayoutListIcon className="h-4 w-4" />
                ) : (
                  <SlidersHorizontalIcon className="h-4 w-4" />
                )}
              </button>
              <div className="relative">
                <button
                  type="button"
                  onClick={() => setColPickerOpen((v) => !v)}
                  className="inline-flex h-9 items-center gap-1.5 rounded-md border border-border bg-card/90 px-3 text-sm text-muted-foreground shadow-sm transition-colors hover:bg-accent hover:text-foreground"
                  title="Choose columns"
                >
                  <LayoutGridIcon className="h-4 w-4" />
                </button>
              </div>
            </div>

            {/* Row 2: status quick-filter pills */}
            <div className="flex min-w-0 items-center gap-1 overflow-x-auto rounded-md border border-border bg-muted/55 p-1 shadow-sm">
              {statusOptions.map((opt) => {
                const isActive = opt.key === "all"
                  ? !filters.some((f) => f.field === "status")
                  : filters.some((f) => f.field === "status" && f.value === opt.key);
                return (
                  <button
                    key={opt.key}
                    type="button"
                    onClick={() => {
                      if (opt.key === "all") {
                        setFilters((prev) => prev.filter((f) => f.field !== "status"));
                      } else {
                        setFilters((prev) => {
                          const rest = prev.filter((f) => f.field !== "status");
                          if (isActive) return rest;
                          return [...rest, {
                            id: crypto.randomUUID(),
                            field: "status",
                            operator: "is",
                            value: opt.key,
                            label: buildFilterLabel("status", "is", opt.label),
                          }];
                        });
                      }
                    }}
                    className={cn(
                      "h-7 whitespace-nowrap rounded px-2.5 text-xs font-semibold transition-colors",
                      isActive
                        ? "bg-card text-foreground shadow-sm"
                        : "text-muted-foreground hover:bg-accent hover:text-foreground"
                    )}
                  >
                    {opt.label}
                  </button>
                );
              })}
            </div>

            {/* Row 3: active filter chips + add filter */}
            <div className="flex flex-wrap items-center gap-1.5">
              {filters
                .filter((f) => f.field !== "status")
                .map((f) => (
                  <span
                    key={f.id}
                    className="inline-flex h-7 items-center gap-1.5 rounded border border-border bg-accent/60 px-2 text-xs font-medium text-foreground"
                  >
                    {f.label}
                    <button
                      type="button"
                      onClick={() => setFilters((prev) => prev.filter((x) => x.id !== f.id))}
                      className="ml-0.5 inline-flex h-4 w-4 items-center justify-center rounded-sm text-muted-foreground hover:text-foreground"
                    >
                      <XIcon className="h-3 w-3" />
                    </button>
                  </span>
                ))}
              <div>
                <button
                  type="button"
                  onClick={(event) => {
                    const rect = event.currentTarget.getBoundingClientRect();
                    const popover = document.getElementById("add-filter-popover");
                    if (popover) {
                      popover.style.left = `${rect.left}px`;
                      popover.style.top = `${rect.bottom + 4}px`;
                    }
                    setAddFilterOpen((prev) => !prev);
                  }}
                  className="inline-flex h-7 items-center gap-1 rounded border border-dashed border-border px-2 text-xs font-medium text-muted-foreground hover:border-ring hover:text-foreground transition-colors"
                >
                  <PlusIcon className="h-3 w-3" />
                  Add filter
                </button>
              </div>
            </div>

          </div>
        </div>
      </header>

      {error && (
        <div className="flex items-center justify-between shrink-0 border-b border-destructive/20 bg-destructive/10 px-5 py-2 text-sm text-destructive">
          <span>{error}</span>
          <button type="button" onClick={() => fetchData()} className="ml-3 text-xs font-medium underline hover:no-underline">
            Retry
          </button>
        </div>
      )}

      <div className="grid min-h-0 flex-1 grid-cols-1 xl:grid-cols-[minmax(0,1fr)_372px]">
        <section className="min-w-0 overflow-auto bg-card/48">
          <div className="min-w-[760px]">
            {filteredTickets.length === 0 ? (
              <div className="flex min-h-80 flex-col items-center justify-center px-5 text-center">
                <div className="mb-3 flex h-11 w-11 items-center justify-center rounded-md border border-border bg-background">
                  <SearchIcon className="h-5 w-5 text-muted-foreground" />
                </div>
                <p className="text-sm font-medium text-foreground">No tickets in this view</p>
                <p className="mt-1 max-w-sm text-sm text-muted-foreground">
                  Adjust the filters or create a new ticket for this queue.
                </p>
                <Button onClick={() => setDialogOpen(true)} className="mt-4 h-8" size="sm">
                  <PlusIcon className="h-4 w-4" />
                  New ticket
                </Button>
              </div>
            ) : (
              <>
                {/* Table layout for consistent column alignment */}
                <div style={{ display: "table", tableLayout: "fixed", minWidth: "100%" }}>
                  {/* Column header */}
                  <div className={cn(
                    "sticky top-0 z-10 border-b border-border bg-muted/50",
                    density === "compact" ? "min-h-7" : "min-h-8"
                  )} style={{ display: "table-row" }}>
                    <div style={{ display: "table-cell", width: 36 }} />
                    {availableColumns.filter((c) => c.visible).map((col, idx, arr) => (
                      <div
                        key={col.key}
                        className="relative border-r border-border/60 px-3 align-middle last:border-r-0"
                        style={{ display: "table-cell", width: col.width }}
                      >
                        {/* Resize handle: drags the boundary, resizes column to the LEFT */}
                        {idx > 0 && (
                          <div
                            className="absolute left-0 top-0 h-full w-3 -ml-1.5 cursor-col-resize hover:bg-primary/30 z-10"
                            onMouseDown={(e) => handleColumnResize(arr[idx - 1].key, col.key, e)}
                          />
                        )}
                        <span className="text-[10px] font-semibold uppercase text-muted-foreground/60 truncate block">
                          {col.label}
                        </span>
                      </div>
                    ))}
                    <div style={{ display: "table-cell", width: 48 }} />
                  </div>

                  {filteredTickets.map((ticket) => {
                    const selected = ticket.id === selectedId;
                    const ownerName = ticket.owner_id
                      ? users.find((u) => u.id === ticket.owner_id)?.username ?? "assigned"
                      : null;

                    return (
                      <div
                        key={ticket.id}
                        role="button"
                        tabIndex={0}
                        onClick={() => setSelectedId(ticket.id)}
                        onDoubleClick={() => router.push(`/tickets/${ticket.id}`)}
                        onKeyDown={(e) => { if (e.key === "Enter") router.push(`/tickets/${ticket.id}`); }}
                        className={cn(
                          "cursor-pointer border-b border-border/80",
                          density === "compact" ? "" : "",
                          selected
                            ? "bg-accent/80 shadow-[inset_3px_0_0_var(--primary)]"
                            : "hover:bg-accent/45"
                        )}
                        style={{ display: "table-row" }}
                      >
                        <div className="flex items-center justify-center" style={{ display: "table-cell", width: 36, verticalAlign: "middle" }} onClick={(e) => e.stopPropagation()}>
                          <input
                            type="checkbox"
                            checked={batchIds.has(ticket.id)}
                            onChange={() => toggleBatchId(ticket.id)}
                            className="h-3.5 w-3.5 rounded border-border accent-primary"
                          />
                        </div>
                        {availableColumns.filter((c) => c.visible).map((col) => {
                          const cellStyle = {
                            display: "table-cell" as const,
                            width: col.width,
                            verticalAlign: "middle" as const,
                            padding: density === "compact" ? "4px 12px" : "8px 12px",
                          };

                          if (col.key.startsWith("cf.")) {
                            const cfKey = col.key.slice(3);
                            const cfValue = ticket.custom_fields?.find((v) => v.custom_field?.key === cfKey || v.custom_field?.name === cfKey)?.value;
                            return (
                              <div key={col.key} className="truncate text-sm text-foreground" style={cellStyle}>
                                {cfValue ?? "—"}
                              </div>
                            );
                          }
                          switch (col.key) {
                            case "id":
                              return (
                                <div key={col.key} className="font-mono text-xs font-semibold text-muted-foreground" style={cellStyle}>
                                  {formatTicketId(ticket.id)}
                                </div>
                              );
                            case "subject":
                              return (
                                <div key={col.key} className="min-w-[200px]" style={cellStyle}>
                                  <span className="block truncate text-sm font-semibold text-foreground">
                                    {ticket.subject}
                                  </span>
                                  {density === "comfortable" && (
                                    <span className="mt-0.5 flex items-center gap-2 text-xs text-muted-foreground">
                                      {ownerName ?? "Unassigned"}
                                      <span className="h-1 w-1 rounded-full bg-border" />
                                      Created {relativeTime(ticket.created_at)}
                                    </span>
                                  )}
                                </div>
                              );
                            case "status":
                              return (
                                <div key={col.key} style={cellStyle}>
                                  <TicketStatusBadge status={ticket.status} />
                                </div>
                              );
                            case "queue":
                              return (
                                <div key={col.key} className="truncate text-sm font-medium text-muted-foreground" style={cellStyle}>
                                  {queueName(queues, ticket.queue_id)}
                                </div>
                              );
                            case "owner":
                              return (
                                <div key={col.key} className="truncate text-sm text-foreground" style={cellStyle}>
                                  {ownerName ?? "—"}
                                </div>
                              );
                            case "created":
                              return (
                                <div key={col.key} className="text-xs text-muted-foreground" style={cellStyle}>
                                  {relativeTime(ticket.created_at)}
                                </div>
                              );
                            case "updated":
                              return (
                                <div key={col.key} className="text-xs text-muted-foreground" style={cellStyle}>
                                  {relativeTime(ticket.updated_at)}
                                </div>
                              );
                            default:
                              return <div key={col.key} style={cellStyle} />;
                          }
                        })}
                        <div className="flex justify-end px-2 text-muted-foreground" style={{ display: "table-cell", width: 48, verticalAlign: "middle" }}>
                          <ChevronRightIcon className="h-4 w-4" />
                        </div>
                      </div>
                    );
                  })}
                </div>
              </>
            )}
          </div>
        </section>

        {/* Floating batch action bar */}
        {batchIds.size > 0 && (
          <div className="sticky bottom-0 z-20 flex items-center gap-3 border-t border-border bg-card/95 px-5 py-3 shadow-lg backdrop-blur">
            <span className="text-sm font-semibold tabular-nums text-foreground">
              {batchIds.size} selected
            </span>
            <button type="button" onClick={() => setBatchIds(new Set())} className="text-xs text-muted-foreground hover:text-foreground">
              Clear
            </button>
            <div className="ml-auto flex items-center gap-2">
              <span className="text-xs text-muted-foreground">Status:</span>
              {statusOptions.filter((s) => s.key !== "all").slice(0, 5).map((s) => (
                <button
                  key={s.key}
                  type="button"
                  disabled={batchSaving}
                  onClick={() => handleBatchStatus(s.key)}
                  className="rounded bg-muted/60 px-2.5 py-1 text-xs font-semibold text-foreground hover:bg-accent disabled:opacity-50"
                >
                  {s.label}
                </button>
              ))}
              <div className="mx-2 h-5 w-px bg-border" />
              <button
                type="button"
                disabled={batchSaving}
                onClick={handleBatchAssign}
                className="rounded bg-primary px-3 py-1 text-xs font-semibold text-primary-foreground hover:bg-primary/90 disabled:opacity-50"
              >
                {batchSaving ? "Saving..." : "Assign to me"}
              </button>
            </div>
          </div>
        )}

        <aside className="hidden min-h-0 border-l border-border bg-card/76 backdrop-blur xl:flex xl:flex-col">
          {selectedTicket ? (
            <>
              <div className="border-b border-border bg-card/82 p-4">
                <div className="flex items-start justify-between gap-2">
                  <div className="min-w-0">
                    <p className="font-mono text-[11px] font-semibold text-muted-foreground">
                      {formatTicketId(selectedTicket.id)}
                    </p>
                    <h2 className="mt-1 text-sm font-semibold leading-snug text-foreground line-clamp-2">
                      {selectedTicket.subject}
                    </h2>
                    <p className="mt-1 text-xs text-muted-foreground">
                      {queueName(queues, selectedTicket.queue_id)} · {selectedTicket.owner_id ? users.find((u) => u.id === selectedTicket.owner_id)?.username ?? "assigned" : "unassigned"}
                    </p>
                  </div>
                  <TicketStatusBadge status={selectedTicket.status} />
                </div>

                <div className="mt-3 flex flex-wrap gap-1">
                  {statusOptions.filter((s) => s.key !== "all").slice(0, 4).map((s) => {
                    const allowed = selectedTicket.status !== s.key;
                    return (
                      <button
                        key={s.key}
                        type="button"
                        disabled={!allowed}
                        onClick={() => handleQuickStatus(selectedTicket.id, s.key)}
                        className={cn(
                          "rounded px-2 py-1 text-[11px] font-semibold transition-colors",
                          selectedTicket.status === s.key
                            ? "bg-primary/10 text-primary"
                            : allowed
                              ? "bg-muted/60 text-muted-foreground hover:bg-accent hover:text-foreground"
                              : "cursor-default text-muted-foreground/40"
                        )}
                      >
                        {s.label}
                      </button>
                    );
                  })}
                </div>

                <div className="mt-2 flex gap-2">
                  <Button
                    onClick={() => router.push(`/tickets/${selectedTicket.id}`)}
                    className="h-7 flex-1 bg-primary text-xs"
                    size="sm"
                  >
                    Open full view
                    <ChevronRightIcon className="ml-1 h-3.5 w-3.5" />
                  </Button>
                  {!selectedTicket.owner_id && (
                    <Button
                      variant="outline"
                      size="sm"
                      onClick={() => handleQuickAssign(selectedTicket.id)}
                      className="h-7 text-xs"
                    >
                      Assign to me
                    </Button>
                  )}
                </div>
              </div>

              <div className="flex-1 overflow-auto">
                {selectedTxs.length === 0 ? (
                  <div className="p-4 text-center text-xs text-muted-foreground">
                    No activity yet.
                  </div>
                ) : (
                  <div className="divide-y divide-border/50">
                    {selectedTxs.slice(0, 8).map((tx) => (
                      <div key={tx.id} className="px-4 py-2.5">
                        <div className="flex items-center gap-2">
                          <span className="text-[11px] font-semibold text-foreground">
                            {tx.transaction_type === "Create" ? "Created" :
                             tx.transaction_type === "StatusChange" ? "Status changed" :
                             tx.transaction_type === "SetOwner" ? "Owner changed" :
                             tx.transaction_type === "Comment" ? "Comment" :
                             tx.transaction_type === "Correspond" ? "Reply" :
                             tx.transaction_type === "SetTeam" ? "Team changed" :
                             tx.transaction_type === "CustomFieldChange" ? `${tx.field} set` :
                             tx.transaction_type}
                          </span>
                          {tx.transaction_type === "StatusChange" && tx.new_value && (
                            <span className={cn(
                              "inline-flex items-center rounded px-1.5 py-0.5 text-[10px] font-semibold",
                              STATUS_META[tx.new_value]?.tone ?? "bg-muted text-muted-foreground"
                            )}>
                              {statusLabel(tx.new_value)}
                            </span>
                          )}
                          {tx.old_value && tx.new_value && tx.transaction_type !== "StatusChange" && (
                            <span className="text-[10px] text-muted-foreground">
                              {tx.old_value} → {tx.new_value}
                            </span>
                          )}
                        </div>
                        {tx.data && (tx.data as any).body && (
                          <p className="mt-1 line-clamp-2 text-xs leading-relaxed text-muted-foreground">
                            {(tx.data as any).body}
                          </p>
                        )}
                        <p className="mt-0.5 text-[10px] text-muted-foreground/60">
                          {formatDistanceToNow(new Date(tx.created_at), { addSuffix: true })}
                        </p>
                      </div>
                    ))}
                  </div>
                )}
              </div>
            </>
          ) : (
            <div className="flex flex-1 flex-col items-center justify-center gap-2 p-6 text-center">
              <div className="flex h-10 w-10 items-center justify-center rounded-full bg-muted/50">
                <ChevronRightIcon className="h-5 w-5 text-muted-foreground/40" />
              </div>
              <p className="text-sm text-muted-foreground">Select a ticket</p>
              <p className="text-xs text-muted-foreground/60">Quick actions and activity will appear here</p>
            </div>
          )}
        </aside>
      </div>

      <Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
        <DialogContent className="sm:max-w-2xl" showCloseButton>
          <DialogHeader>
            <DialogTitle>New ticket</DialogTitle>
            <DialogDescription>
              Create a request, incident, task, or follow-up for the right queue.
            </DialogDescription>
          </DialogHeader>

          <div className="grid gap-3">
            <label className="grid gap-1.5 text-sm font-medium">
              Subject
              <input
                value={newSubject}
                onChange={(event) => setNewSubject(event.target.value)}
                placeholder="Short summary"
                className="h-9 rounded-md border border-input bg-background px-3 text-sm font-normal outline-none focus:border-ring"
                autoFocus
              />
            </label>

            <label className="grid gap-1.5 text-sm font-medium">
              Queue
              <select
                value={newQueueId}
                onChange={(event) => {
                  setNewQueueId(event.target.value);
                  setCreateError(null);
                }}
                className="h-9 rounded-md border border-input bg-background px-3 text-sm font-normal outline-none focus:border-ring"
              >
                <option value="" disabled>
                  Select queue
                </option>
                {queues.map((queue) => (
                  <option key={queue.id} value={queue.id}>
                    {queue.name}
                  </option>
                ))}
              </select>
              <span className="text-xs font-normal text-muted-foreground">
                Starts as <span className="font-mono text-foreground">{newTicketInitialStatus}</span>
                {selectedNewLifecycle ? ` from ${selectedNewLifecycle.name}` : ""}
              </span>
            </label>

            <label className="grid gap-1.5 text-sm font-medium">
              Description
              <textarea
                value={newDescription}
                onChange={(event) => setNewDescription(event.target.value)}
                placeholder="Optional context"
                rows={4}
                className="resize-none rounded-md border border-input bg-background px-3 py-2 text-sm font-normal outline-none focus:border-ring"
              />
            </label>

            {(newFieldsLoading || newTicketFields.length > 0) && (
              <div className="rounded-md border border-border bg-muted/25">
                <div className="border-b border-border px-3 py-2">
                  <div className="text-sm font-semibold text-foreground">Queue fields</div>
                  <div className="mt-0.5 text-xs text-muted-foreground">
                    Metadata attached to this ticket from the selected queue.
                  </div>
                </div>
                <div className="grid gap-3 p-3">
                  {newFieldsLoading ? (
                    <div className="h-9 animate-pulse rounded-md bg-muted" />
                  ) : (
                    newTicketFields.map((field) => {
                      const options = Array.isArray(field.values)
                        ? field.values.map((value) => String(value))
                        : [];
                      return (
                        <label key={field.id} className="grid gap-1.5 text-sm font-medium">
                          <span className="flex min-w-0 items-center justify-between gap-3">
                            <span className="truncate">{field.name}</span>
                            <span className="shrink-0 font-mono text-[11px] font-normal text-muted-foreground">{field.key}</span>
                          </span>
                          {options.length > 0 ? (
                            <select
                              value={newCustomFieldValues[field.id] ?? ""}
                              onChange={(event) => setNewCustomFieldValues((current) => ({
                                ...current,
                                [field.id]: event.target.value,
                              }))}
                              className="h-9 rounded-md border border-input bg-background px-3 text-sm font-normal outline-none focus:border-ring"
                            >
                              <option value="">No value</option>
                              {options.map((option) => (
                                <option key={option} value={option}>{option}</option>
                              ))}
                            </select>
                          ) : (
                            <input
                              value={newCustomFieldValues[field.id] ?? ""}
                              onChange={(event) => setNewCustomFieldValues((current) => ({
                                ...current,
                                [field.id]: event.target.value,
                              }))}
                              placeholder={field.pattern ? `Pattern: ${field.pattern}` : "Optional value"}
                              className="h-9 rounded-md border border-input bg-background px-3 text-sm font-normal outline-none focus:border-ring"
                            />
                          )}
                          {field.pattern && (
                            <span className="text-[11px] text-muted-foreground">
                              Must match: <code className="rounded bg-muted px-1 font-mono">{field.pattern}</code>
                            </span>
                          )}
                        </label>
                      );
                    })
                  )}
                </div>
              </div>
            )}
          </div>

          {createError && <p className="text-sm text-destructive">{createError}</p>}

          <DialogFooter showCloseButton={false}>
            <Button
              onClick={handleCreate}
              disabled={!newSubject.trim() || !newQueueId || submitting}
            >
              {submitting ? "Creating..." : "Create ticket"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <Dialog open={saveViewOpen} onOpenChange={setSaveViewOpen}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Save view</DialogTitle>
            <DialogDescription>
              Save the current filters as a named view. It will appear in your sidebar.
            </DialogDescription>
          </DialogHeader>
          <input
            value={saveViewName}
            onChange={(event) => setSaveViewName(event.target.value)}
            placeholder="View name"
            className="h-9 w-full rounded-md border border-input bg-card px-3 text-sm outline-none focus:border-ring"
            autoFocus
            onKeyDown={async (event) => {
              if (event.key === "Enter" && saveViewName.trim()) {
                const storedFilters = filters.map((f) => ({
                  field: f.field,
                  operator: f.operator,
                  value: f.value,
                }));
                const { data, error } = await createView({
                  name: saveViewName.trim(),
                  filters: storedFilters,
                  sort_key: sortKey,
                  columns,
                });
                if (!error && data) {
                  setSavedViewsList((prev) => [...prev, data]);
                  setSaveViewOpen(false);
                  setSaveViewName("");
                }
              }
            }}
          />
          <DialogFooter>
            <Button
              variant="outline"
              size="sm"
              onClick={() => setSaveViewOpen(false)}
            >
              Cancel
            </Button>
            <Button
              size="sm"
              disabled={!saveViewName.trim()}
              onClick={async () => {
                if (!saveViewName.trim()) return;
                const storedFilters = filters.map((f) => ({
                  field: f.field,
                  operator: f.operator,
                  value: f.value,
                }));
                const { data, error } = await createView({
                  name: saveViewName.trim(),
                  filters: storedFilters,
                  sort_key: sortKey,
                  columns,
                });
                if (!error && data) {
                  setSavedViewsList((prev) => [...prev, data]);
                  setSaveViewOpen(false);
                  setSaveViewName("");
                }
              }}
            >
              Save
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {typeof document !== "undefined" && addFilterOpen && createPortal(
        <>
          <div
            className="fixed inset-0 z-[9998]"
            onClick={() => {
              setAddFilterOpen(false);
              setAddFilterField(null);
            }}
          />
          <div
            id="add-filter-popover"
            className="fixed z-[9999] w-52 rounded-md border border-border bg-popover p-1 shadow-lg"
          >
            {!addFilterField ? (
              <>
                <button
                  type="button"
                  className="w-full rounded px-2 py-1.5 text-left text-xs text-foreground hover:bg-accent"
                  onClick={() => {
                    if (!filters.find((f) => f.field === "queue")) {
                      setAddFilterField("queue");
                      setAddFilterOperator("is");
                      setAddFilterValue("");
                    } else {
                      setAddFilterOpen(false);
                    }
                  }}
                >Queue</button>
                <button
                  type="button"
                  className="w-full rounded px-2 py-1.5 text-left text-xs text-foreground hover:bg-accent"
                  onClick={() => {
                    if (!filters.find((f) => f.field === "owner")) {
                      setAddFilterField("owner");
                      setAddFilterOperator("is");
                      setAddFilterValue("");
                    } else {
                      setAddFilterOpen(false);
                    }
                  }}
                >Owner</button>
                {customFields.map((cf) => (
                  <button
                    key={`cf-portal-${cf.id}`}
                    type="button"
                    className="w-full rounded px-2 py-1.5 text-left text-xs text-foreground hover:bg-accent"
                    onClick={() => {
                      setAddFilterField(`cf.${cf.key}`);
                      setAddFilterOperator("is");
                      setAddFilterValue("");
                    }}
                  >{cf.name}</button>
                ))}
              </>
            ) : (
              <div className="space-y-2 p-1">
                <div className="flex items-center gap-1 text-xs">
                  <button type="button" onClick={() => setAddFilterField(null)} className="text-muted-foreground hover:text-foreground">←</button>
                  <span className="font-medium text-foreground">{addFilterField.startsWith("cf.") ? addFilterField.slice(3) : addFilterField}</span>
                </div>
                <select value={addFilterOperator} onChange={(e) => setAddFilterOperator(e.target.value)} className="h-7 w-full rounded border border-input bg-card px-2 text-xs outline-none">
                  <option value="is">is</option>
                  <option value="is_not">is not</option>
                </select>
                {addFilterField === "queue" ? (
                  <select value={addFilterValue} onChange={(e) => setAddFilterValue(e.target.value)} className="h-7 w-full rounded border border-input bg-card px-2 text-xs outline-none">
                    <option value="">Select queue...</option>
                    {queues.map((q) => (<option key={q.id} value={q.id}>{q.name}</option>))}
                  </select>
                ) : addFilterField === "owner" ? (
                  <select value={addFilterValue} onChange={(e) => setAddFilterValue(e.target.value)} className="h-7 w-full rounded border border-input bg-card px-2 text-xs outline-none">
                    <option value="">Select owner...</option>
                    <option value="unassigned">Unassigned</option>
                    {users.map((u) => (<option key={u.id} value={u.id}>{u.username}</option>))}
                  </select>
                ) : (
                  <input value={addFilterValue} onChange={(e) => setAddFilterValue(e.target.value)} placeholder="Value" className="h-7 w-full rounded border border-input bg-card px-2 text-xs outline-none"
                    onKeyDown={(e) => {
                      if (e.key === "Enter" && addFilterValue.trim()) {
                        setFilters((prev) => [...prev, { id: crypto.randomUUID(), field: addFilterField, operator: addFilterOperator, value: addFilterValue, label: buildFilterLabel(addFilterField, addFilterOperator, addFilterValue) }]);
                        setAddFilterField(null);
                        setAddFilterOpen(false);
                      }
                    }}
                  />
                )}
                <div className="flex items-center justify-end gap-1 pt-1">
                  <button type="button" onClick={() => { setAddFilterField(null); setAddFilterOpen(false); }} className="rounded px-2 py-1 text-xs text-muted-foreground hover:text-foreground">Cancel</button>
                  <button type="button" disabled={!addFilterValue.trim()}
                    onClick={() => {
                      if (!addFilterValue.trim()) return;
                      const field = addFilterField;
                      const value = addFilterValue;
                      let valueLabel = value;
                      if (field === "queue") valueLabel = queues.find((q) => q.id === value)?.name ?? value;
                      else if (field === "owner") valueLabel = value === "unassigned" ? "Unassigned" : users.find((u) => u.id === value)?.username ?? value;
                      setFilters((prev) => [...prev, { id: crypto.randomUUID(), field, operator: addFilterOperator, value, label: buildFilterLabel(field, addFilterOperator, valueLabel) }]);
                      setAddFilterField(null);
                      setAddFilterOpen(false);
                    }}
                    className="rounded bg-primary px-2 py-1 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50"
                  >Apply</button>
                </div>
              </div>
            )}
          </div>
        </>,
        document.body
      )}

      {typeof document !== "undefined" && colPickerOpen && createPortal(
        <>
          <div className="fixed inset-0 z-[9998]" onClick={() => setColPickerOpen(false)} />
          <div className="fixed z-[9999] w-48 rounded-md border border-border bg-card p-1 shadow-lg"
            style={{ left: "calc(100% - 220px)", top: "72px" }}
          >
            {availableColumns.map((col) => {
              const isVisible = columns.find((c) => c.key === col.key)?.visible ?? col.visible;
              return (
                <button
                  key={col.key}
                  type="button"
                  onClick={() => {
                    setColumns((prev) =>
                      prev.map((c) => c.key === col.key ? { ...c, visible: !c.visible } : c)
                    );
                  }}
                  className="flex w-full items-center gap-2 rounded px-2 py-1.5 text-xs text-foreground hover:bg-accent"
                >
                  <span className={cn("text-xs", isVisible ? "text-primary" : "text-muted-foreground/30")}>
                    {isVisible ? "✓" : "—"}
                  </span>
                  {col.label}
                </button>
              );
            })}
          </div>
        </>,
        document.body
      )}
    </div>
  );
}

export default function TicketWorkbenchPage() {
  return (
    <Suspense fallback={<SkeletonWorkbench />}>
      <TicketWorkbenchContent />
    </Suspense>
  );
}
