"use client";

import { useState, useCallback } from "react";
import Link from "next/link";
import { VacationStatus, VacationType } from "@nexus/shared";
import { trpc } from "~/lib/trpc/client.js";
import { VacationModal } from "./VacationModal.js";
import { TeamCalendar } from "./TeamCalendar.js";
import { FilterChips } from "~/components/ui/FilterChips.js";
import { SortableColumnHeader } from "~/components/ui/SortableColumnHeader.js";
import { useTableSort } from "~/hooks/useTableSort.js";
import { useViewPrefs } from "~/hooks/useViewPrefs.js";
import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
import {
  VACATION_STATUS_BADGE as STATUS_BADGE,
  VACATION_TYPE_LABELS as TYPE_LABELS,
  VACATION_TYPE_BADGE,
} from "~/lib/status-styles.js";
import { SuccessToast } from "~/components/ui/SuccessToast.js";

type VacationStatusFilter = VacationStatus | "ALL";
type VacationTypeFilter = VacationType | "ALL";
type Tab = "list" | "team-calendar";

export function VacationClient() {
  const [tab, setTab] = useState<Tab>("list");
  const [showModal, setShowModal] = useState(false);
  const [statusFilter, setStatusFilter] = useState<VacationStatusFilter>("ALL");
  const [typeFilter, setTypeFilter] = useState<VacationTypeFilter>("ALL");
  const [resourceFilter, setResourceFilter] = useState<string>("");
  const [selected, setSelected] = useState<Set<string>>(new Set());
  const [batchRejectReason, setBatchRejectReason] = useState("");
  const [showBatchRejectInput, setShowBatchRejectInput] = useState(false);
  const [toast, setToast] = useState<{
    show: boolean;
    message: string;
    variant: "success" | "warning";
  }>({
    show: false,
    message: "",
    variant: "success",
  });
  const clearToast = useCallback(() => setToast((t) => ({ ...t, show: false })), []);

  const {
    data: vacations,
    isLoading,
    error: vacationError,
    refetch,
  } = trpc.vacation.list.useQuery(
    {
      ...(statusFilter !== "ALL" ? { status: statusFilter } : {}),
      ...(typeFilter !== "ALL" ? { type: typeFilter } : {}),
      ...(resourceFilter ? { resourceId: resourceFilter } : {}),
      limit: 200,
    },
    { staleTime: 15_000 },
  );

  const { data: resources } = trpc.resource.directory.useQuery(
    { isActive: true, limit: 500 },
    { staleTime: 60_000 },
  );

  const { data: pending } = trpc.vacation.getPendingApprovals.useQuery(undefined, {
    staleTime: 15_000,
  });

  const utils = trpc.useUtils();

  function invalidateAll() {
    return Promise.all([
      utils.vacation.list.invalidate(),
      utils.vacation.getPendingApprovals.invalidate(),
      utils.entitlement.getBalance.invalidate(),
    ]);
  }

  const approveMutation = trpc.vacation.approve.useMutation({ onSuccess: invalidateAll });
  const rejectMutation = trpc.vacation.reject.useMutation({ onSuccess: invalidateAll });
  const cancelMutation = trpc.vacation.cancel.useMutation({
    onSuccess: () => utils.vacation.list.invalidate(),
  });
  const batchApproveMutation = trpc.vacation.batchApprove.useMutation({
    onSuccess: async () => {
      setSelected(new Set());
      setToast({ show: true, message: "Vacations approved", variant: "success" });
      await invalidateAll();
    },
  });
  const batchRejectMutation = trpc.vacation.batchReject.useMutation({
    onSuccess: async () => {
      setSelected(new Set());
      setShowBatchRejectInput(false);
      setBatchRejectReason("");
      setToast({ show: true, message: "Vacations rejected", variant: "warning" });
      await invalidateAll();
    },
  });

  const resourceList = (resources?.resources ?? []) as unknown as Array<{
    id: string;
    displayName: string;
    eid: string;
  }>;
  const vacationList = vacations ?? [];
  const pendingList = pending ?? [];

  const vacViewPrefs = useViewPrefs("vacations");
  const { sorted, sortField, sortDir, toggle } = useTableSort(vacationList, {
    initialField: vacViewPrefs.savedSort?.field ?? null,
    initialDir: vacViewPrefs.savedSort?.dir ?? null,
    onSortChange: (field, dir) => {
      vacViewPrefs.setSavedSort(field && dir ? { field, dir } : null);
    },
  });

  function handleSort(field: string) {
    if (field === "resource") {
      toggle(
        "resource",
        (v) => (v.resource as { displayName: string } | undefined)?.displayName ?? null,
      );
    } else {
      toggle(field);
    }
  }

  function clearAll() {
    setStatusFilter("ALL");
    setTypeFilter("ALL");
    setResourceFilter("");
  }

  const selectedResourceName = resourceFilter
    ? resourceList.find((r) => r.id === resourceFilter)?.displayName
    : null;

  const chips = [
    ...(statusFilter !== "ALL"
      ? [{ label: `Status: ${statusFilter}`, onRemove: () => setStatusFilter("ALL") }]
      : []),
    ...(typeFilter !== "ALL"
      ? [{ label: `Type: ${TYPE_LABELS[typeFilter]}`, onRemove: () => setTypeFilter("ALL") }]
      : []),
    ...(resourceFilter
      ? [
          {
            label: `Resource: ${selectedResourceName ?? resourceFilter}`,
            onRemove: () => setResourceFilter(""),
          },
        ]
      : []),
  ];

  const pendingIds = pendingList.map((v) => v.id);
  const selectedPending = [...selected].filter((id) => pendingIds.includes(id));
  const allPendingSelected = pendingIds.length > 0 && pendingIds.every((id) => selected.has(id));

  function toggleSelectAll() {
    if (allPendingSelected) {
      setSelected(new Set());
    } else {
      setSelected(new Set(pendingIds));
    }
  }

  return (
    <div className="p-6 max-w-5xl mx-auto space-y-6">
      <SuccessToast
        show={toast.show}
        message={toast.message}
        variant={toast.variant}
        onDone={clearToast}
      />
      {/* Header */}
      <div className="flex items-center justify-between">
        <div>
          <h1 className="text-2xl font-bold text-gray-900 dark:text-gray-100">Vacations</h1>
          <p className="text-sm text-gray-500 dark:text-gray-400 mt-1">
            Manage vacation requests and approvals
          </p>
          <p className="mt-2 text-xs text-gray-500 dark:text-gray-400">
            Regional public holidays are maintained in{" "}
            <Link
              href="/admin/vacations"
              className="font-medium text-brand-700 hover:text-brand-800 dark:text-brand-400 dark:hover:text-brand-300"
            >
              Holiday Calendars
            </Link>
            .
          </p>
        </div>
        <button
          type="button"
          onClick={() => setShowModal(true)}
          className="px-4 py-2 bg-brand-600 text-white rounded-lg hover:bg-brand-700 text-sm font-medium"
        >
          + Request Vacation
        </button>
      </div>

      {/* Tabs */}
      <div className="flex gap-1 border-b border-gray-200 dark:border-gray-700">
        {(["list", "team-calendar"] as Tab[]).map((t) => (
          <button
            key={t}
            type="button"
            onClick={() => setTab(t)}
            className={`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${
              tab === t
                ? "border-brand-600 text-brand-700"
                : "border-transparent text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300"
            }`}
          >
            {t === "list" ? "List" : "Team Calendar"}
          </button>
        ))}
      </div>

      {tab === "team-calendar" ? (
        <TeamCalendar />
      ) : (
        <>
          {/* Pending approvals (manager view) */}
          {pendingList.length > 0 && (
            <div className="bg-amber-50 dark:bg-amber-950/30 border border-amber-200 dark:border-amber-700/60 rounded-xl p-4">
              <div className="flex items-center justify-between mb-3">
                <h2 className="text-sm font-semibold text-amber-800 dark:text-amber-400">
                  Pending Approvals ({pendingList.length})
                </h2>
                {/* Batch controls */}
                <div className="flex items-center gap-2">
                  <label className="flex items-center gap-1.5 text-xs text-amber-700 dark:text-amber-400 cursor-pointer">
                    <input
                      type="checkbox"
                      checked={allPendingSelected}
                      onChange={toggleSelectAll}
                      className="rounded border-amber-300 dark:border-amber-600 text-amber-600"
                    />
                    Select all
                  </label>
                  {selectedPending.length > 0 && (
                    <>
                      <button
                        type="button"
                        onClick={() => batchApproveMutation.mutate({ ids: selectedPending })}
                        disabled={batchApproveMutation.isPending}
                        className="px-2 py-1 bg-emerald-600 text-white text-xs rounded hover:bg-emerald-700 disabled:opacity-50"
                      >
                        Approve {selectedPending.length}
                      </button>
                      <button
                        type="button"
                        onClick={() => setShowBatchRejectInput((v) => !v)}
                        className="px-2 py-1 bg-red-600 text-white text-xs rounded hover:bg-red-700"
                      >
                        Reject {selectedPending.length}
                      </button>
                    </>
                  )}
                </div>
              </div>

              {/* Batch reject reason input */}
              {showBatchRejectInput && selectedPending.length > 0 && (
                <div className="mb-3 flex gap-2">
                  <input
                    type="text"
                    placeholder="Rejection reason (optional)…"
                    value={batchRejectReason}
                    onChange={(e) => setBatchRejectReason(e.target.value)}
                    className="flex-1 px-3 py-1.5 text-sm border border-amber-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-red-400"
                  />
                  <button
                    type="button"
                    onClick={() =>
                      batchRejectMutation.mutate({
                        ids: selectedPending,
                        ...(batchRejectReason.trim()
                          ? { rejectionReason: batchRejectReason.trim() }
                          : {}),
                      })
                    }
                    disabled={batchRejectMutation.isPending}
                    className="px-3 py-1.5 bg-red-600 text-white text-xs rounded hover:bg-red-700 disabled:opacity-50"
                  >
                    Confirm Reject
                  </button>
                </div>
              )}

              <div className="space-y-2">
                {pendingList.map((v) => (
                  <div
                    key={v.id}
                    className="flex items-center justify-between bg-white dark:bg-gray-800 rounded-lg px-4 py-2 shadow-sm"
                  >
                    <div className="flex items-center gap-2 flex-1 min-w-0">
                      <input
                        type="checkbox"
                        checked={selected.has(v.id)}
                        onChange={(e) => {
                          const next = new Set(selected);
                          if (e.target.checked) next.add(v.id);
                          else next.delete(v.id);
                          setSelected(next);
                        }}
                        className="rounded border-gray-300 dark:border-gray-600 text-amber-600 shrink-0"
                      />
                      <span className="font-medium text-sm text-gray-900 dark:text-gray-100">
                        {v.resource.displayName}
                      </span>
                      <span className="text-xs text-gray-500 dark:text-gray-400">
                        ({v.resource.eid})
                      </span>
                      <span className="mx-1 text-gray-300 dark:text-gray-600">·</span>
                      <span
                        className={`inline-flex px-1.5 py-0.5 rounded-full text-xs font-medium ${VACATION_TYPE_BADGE[v.type as string] ?? "bg-gray-100 text-gray-600"}`}
                      >
                        {TYPE_LABELS[v.type as VacationType]}
                      </span>
                      <span className="mx-1 text-gray-300 dark:text-gray-600">·</span>
                      <span className="text-xs text-gray-500 dark:text-gray-400">
                        {new Date(v.startDate).toLocaleDateString("en-GB")} –{" "}
                        {new Date(v.endDate).toLocaleDateString("en-GB")}
                      </span>
                      {v.note && (
                        <span className="text-xs text-gray-400 ml-2 italic truncate">{v.note}</span>
                      )}
                    </div>
                    <div className="flex gap-2 ml-4 shrink-0">
                      <button
                        type="button"
                        onClick={() => approveMutation.mutate({ id: v.id })}
                        disabled={approveMutation.isPending}
                        className="px-3 py-1 bg-emerald-600 text-white text-xs rounded hover:bg-emerald-700 disabled:opacity-50"
                      >
                        Approve
                      </button>
                      <button
                        type="button"
                        onClick={() => rejectMutation.mutate({ id: v.id })}
                        disabled={rejectMutation.isPending}
                        className="px-3 py-1 bg-red-600 text-white text-xs rounded hover:bg-red-700 disabled:opacity-50"
                      >
                        Reject
                      </button>
                    </div>
                  </div>
                ))}
              </div>
            </div>
          )}

          {/* Filters */}
          <div className="flex flex-wrap gap-3 items-center">
            <select
              value={statusFilter}
              onChange={(e) => setStatusFilter(e.target.value as VacationStatusFilter)}
              className="px-3 py-1.5 text-sm border border-gray-200 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-brand-500 dark:bg-gray-900 dark:text-gray-100"
            >
              <option value="ALL">All statuses</option>
              {Object.values(VacationStatus).map((s) => (
                <option key={s} value={s}>
                  {s}
                </option>
              ))}
            </select>
            <select
              value={typeFilter}
              onChange={(e) => setTypeFilter(e.target.value as VacationTypeFilter)}
              className="px-3 py-1.5 text-sm border border-gray-200 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-brand-500 dark:bg-gray-900 dark:text-gray-100"
            >
              <option value="ALL">All types</option>
              {Object.values(VacationType).map((t) => (
                <option key={t} value={t}>
                  {TYPE_LABELS[t]}
                </option>
              ))}
            </select>
            <select
              value={resourceFilter}
              onChange={(e) => setResourceFilter(e.target.value)}
              className="px-3 py-1.5 text-sm border border-gray-200 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-brand-500 dark:bg-gray-900 dark:text-gray-100"
            >
              <option value="">All resources</option>
              {resourceList.map((r) => (
                <option key={r.id} value={r.id}>
                  {r.displayName} ({r.eid})
                </option>
              ))}
            </select>
          </div>

          {/* Filter chips */}
          {chips.length > 0 && <FilterChips chips={chips} onClearAll={clearAll} />}

          {/* List */}
          <div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 overflow-hidden">
            {isLoading ? (
              <div className="p-8 text-center text-sm text-gray-400">Loading…</div>
            ) : vacationError ? (
              <div className="p-8 text-center text-sm text-red-500">
                Error: {vacationError.message}
              </div>
            ) : vacationList.length === 0 ? (
              <div className="p-8 text-center text-sm text-gray-400">No vacations found.</div>
            ) : (
              <table className="w-full text-sm">
                <thead>
                  <tr className="border-b border-gray-100 dark:border-gray-700 bg-gray-50 dark:bg-gray-900">
                    <SortableColumnHeader
                      label="Resource"
                      field="resource"
                      sortField={sortField}
                      sortDir={sortDir}
                      onSort={handleSort}
                      tooltip="The employee this vacation entry belongs to."
                    />
                    <th className="px-3 py-3 text-xs font-medium text-gray-500 uppercase tracking-wider">
                      <span className="inline-flex items-center gap-0.5">
                        <button
                          type="button"
                          onClick={() => handleSort("type")}
                          className="flex items-center gap-0.5 justify-start w-full hover:text-gray-700 transition-colors group"
                        >
                          Type
                        </button>
                        <InfoTooltip content="ANNUAL = paid annual leave · SICK = sick leave · PUBLIC_HOLIDAY = public holiday · OTHER = other leave types." />
                      </span>
                    </th>
                    <SortableColumnHeader
                      label="Start"
                      field="startDate"
                      sortField={sortField}
                      sortDir={sortDir}
                      onSort={handleSort}
                      tooltip="First day of the leave period (inclusive). Shows a half-day indicator if applicable."
                    />
                    <SortableColumnHeader
                      label="End"
                      field="endDate"
                      sortField={sortField}
                      sortDir={sortDir}
                      onSort={handleSort}
                      tooltip="Last day of the leave period (inclusive)."
                    />
                    <th className="px-3 py-3 text-xs font-medium text-gray-500 uppercase tracking-wider">
                      <span className="inline-flex items-center gap-0.5">
                        <button
                          type="button"
                          onClick={() => handleSort("status")}
                          className="flex items-center gap-0.5 justify-start w-full hover:text-gray-700 transition-colors group"
                        >
                          Status
                        </button>
                        <InfoTooltip content="PENDING = awaiting manager approval · APPROVED = confirmed leave · REJECTED = declined by manager · CANCELLED = withdrawn by employee." />
                      </span>
                    </th>
                    <th className="text-left px-4 py-3 font-medium text-gray-500 dark:text-gray-400 text-xs uppercase tracking-wider">
                      Note / Reason{" "}
                      <InfoTooltip content="Employee's leave note, or manager's rejection reason if status is REJECTED." />
                    </th>
                    <th className="px-4 py-3" />
                  </tr>
                </thead>
                <tbody className="divide-y divide-gray-50 dark:divide-gray-700">
                  {sorted.map((v) => {
                    const type = v.type as VacationType;
                    const status = v.status as VacationStatus;
                    const resource = v.resource as { displayName: string; eid: string } | undefined;
                    const vExtra = v as unknown as {
                      rejectionReason?: string | null;
                      isHalfDay?: boolean;
                    };
                    return (
                      <tr key={v.id} className="hover:bg-gray-50 dark:hover:bg-gray-700/50">
                        <td className="px-4 py-3">
                          <span className="font-medium text-gray-900 dark:text-gray-100">
                            {resource?.displayName ?? "—"}
                          </span>
                          {resource?.eid && (
                            <span className="text-xs text-gray-400 dark:text-gray-500 ml-1">
                              ({resource.eid})
                            </span>
                          )}
                        </td>
                        <td className="px-4 py-3">
                          <span
                            className={`inline-flex px-2 py-0.5 rounded-full text-xs font-medium ${VACATION_TYPE_BADGE[type] ?? "bg-gray-100 text-gray-600"}`}
                          >
                            {TYPE_LABELS[type] ?? type}
                          </span>
                        </td>
                        <td className="px-4 py-3 text-gray-600 dark:text-gray-400">
                          {new Date(v.startDate).toLocaleDateString("en-GB")}
                          {vExtra.isHalfDay && (
                            <span className="ml-1 text-xs text-gray-400 dark:text-gray-500">½</span>
                          )}
                        </td>
                        <td className="px-4 py-3 text-gray-600 dark:text-gray-400">
                          {new Date(v.endDate).toLocaleDateString("en-GB")}
                        </td>
                        <td className="px-4 py-3">
                          <span
                            className={`inline-flex px-2 py-0.5 rounded-full text-xs font-medium ${STATUS_BADGE[status] ?? ""}`}
                          >
                            {status}
                          </span>
                        </td>
                        <td className="px-4 py-3 text-gray-400 dark:text-gray-500 text-xs max-w-xs truncate">
                          {vExtra.rejectionReason ? (
                            <span className="text-red-500">{vExtra.rejectionReason}</span>
                          ) : (
                            (v.note ?? "—")
                          )}
                        </td>
                        <td className="px-4 py-3 text-right space-x-3">
                          {status === VacationStatus.CANCELLED ? (
                            <button
                              type="button"
                              onClick={() => approveMutation.mutate({ id: v.id })}
                              disabled={approveMutation.isPending}
                              className="text-xs text-emerald-600 dark:text-emerald-400 hover:text-emerald-800 underline disabled:opacity-50"
                            >
                              Re-approve
                            </button>
                          ) : (
                            <button
                              type="button"
                              onClick={() => cancelMutation.mutate({ id: v.id })}
                              disabled={cancelMutation.isPending}
                              className="text-xs text-gray-400 hover:text-red-600 underline disabled:opacity-50"
                            >
                              Cancel
                            </button>
                          )}
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            )}
          </div>
        </>
      )}

      {showModal && (
        <VacationModal
          onClose={() => setShowModal(false)}
          onSuccess={() => {
            setShowModal(false);
            void refetch();
          }}
        />
      )}
    </div>
  );
}
