"use client";

import { useRef, useState } from "react";
import { useFocusTrap } from "~/hooks/useFocusTrap.js";
import { VacationType } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js";
import { DateInput } from "~/components/ui/DateInput.js";
import { useDebounce } from "~/hooks/useDebounce.js";
import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
import { VACATION_TYPE_LABELS } from "~/lib/status-styles.js";

const VACATION_TYPES = Object.values(VacationType);
const REQUESTABLE_VACATION_TYPES = VACATION_TYPES.filter((type) => type !== VacationType.PUBLIC_HOLIDAY);

const HOLIDAY_SOURCE_LABELS = {
  CALENDAR: "Calendar",
  LEGACY_PUBLIC_HOLIDAY: "Legacy import",
  CALENDAR_AND_LEGACY: "Calendar + legacy",
} as const;

type VacationPreviewData = {
  requestedDays: number;
  effectiveDays: number;
  deductedDays: number;
  publicHolidayDates: string[];
  holidayDetails: Array<{
    date: string;
    source: string;
  }>;
  holidayContext: {
    countryCode: string | null;
    countryName: string | null;
    federalState: string | null;
    metroCityName: string | null;
    sources: {
      hasCalendarHolidays: boolean;
      hasLegacyPublicHolidayEntries: boolean;
    };
  };
};

interface VacationModalProps {
  resourceId?: string;
  onClose: () => void;
  onSuccess: () => void;
}

function toUtcInputDate(value: string): Date {
  return new Date(`${value}T00:00:00.000Z`);
}

function buildHolidayBasisLabel(preview: VacationPreviewData): string[] {
  const parts = [];

  if (preview.holidayContext.countryName || preview.holidayContext.countryCode) {
    parts.push(preview.holidayContext.countryName ?? preview.holidayContext.countryCode ?? "");
  }

  if (preview.holidayContext.federalState) {
    parts.push(preview.holidayContext.federalState);
  }

  if (preview.holidayContext.metroCityName) {
    parts.push(preview.holidayContext.metroCityName);
  }

  return parts.filter(Boolean);
}

function getHolidaySourceLabel(source: string): string {
  if (source in HOLIDAY_SOURCE_LABELS) {
    return HOLIDAY_SOURCE_LABELS[source as keyof typeof HOLIDAY_SOURCE_LABELS];
  }

  return source;
}

export function VacationModal({ resourceId: initialResourceId, onClose, onSuccess }: VacationModalProps) {
  const [resourceId, setResourceId] = useState(initialResourceId ?? "");
  const [type, setType] = useState<VacationType>(VacationType.ANNUAL);
  const [startDate, setStartDate] = useState("");
  const [endDate, setEndDate] = useState("");
  const [note, setNote] = useState("");
  const [isHalfDay, setIsHalfDay] = useState(false);
  const [halfDayPart, setHalfDayPart] = useState<"MORNING" | "AFTERNOON">("MORNING");
  const [serverError, setServerError] = useState<string | null>(null);

  const panelRef = useRef<HTMLDivElement>(null);
  useFocusTrap(panelRef, true);

  const debouncedStart = useDebounce(startDate, 400);
  const debouncedEnd = useDebounce(endDate, 400);

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

  // Team overlap: other resources in same chapter off in this period
  const { data: teamOverlap } = trpc.vacation.getTeamOverlap.useQuery(
    {
      resourceId: resourceId,
      startDate: debouncedStart ? new Date(debouncedStart) : new Date(),
      endDate: debouncedEnd ? new Date(debouncedEnd) : new Date(),
    },
    {
      enabled: !!resourceId && !!debouncedStart && !!debouncedEnd,
      staleTime: 10_000,
    },
  );

  // Show existing vacations for this resource in the selected period
  const { data: existingVacations } = trpc.vacation.list.useQuery(
    {
      resourceId: resourceId || undefined,
      startDate: startDate ? new Date(startDate) : undefined,
      endDate: endDate ? new Date(endDate) : undefined,
    },
    { enabled: !!resourceId && !!startDate && !!endDate, staleTime: 10_000 },
  );

  const previewQuery = trpc.vacation.previewRequest.useQuery(
    {
      resourceId,
      type,
      startDate: toUtcInputDate(debouncedStart || "1970-01-01"),
      endDate: toUtcInputDate(debouncedEnd || "1970-01-01"),
      ...(isHalfDay ? { isHalfDay: true } : {}),
    },
    {
      enabled:
        !!resourceId
        && !!debouncedStart
        && !!debouncedEnd
        && (!isHalfDay || debouncedStart === debouncedEnd),
      staleTime: 10_000,
    },
  );

  const utils = trpc.useUtils();

  const createMutation = trpc.vacation.create.useMutation({
    onSuccess: async () => {
      await utils.vacation.list.invalidate();
      onSuccess();
    },
    onError: (err) => setServerError(err.message),
  });

  const isPending = createMutation.isPending;

  function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    setServerError(null);

    if (!resourceId || !startDate || !endDate) {
      setServerError("Please fill in all required fields.");
      return;
    }

    const start = new Date(startDate);
    const end = new Date(endDate);
    if (end < start) {
      setServerError("End date must be on or after start date.");
      return;
    }

    createMutation.mutate({
      resourceId,
      type,
      startDate: start,
      endDate: end,
      note: note || undefined,
      isHalfDay,
      ...(isHalfDay ? { halfDayPart } : {}),
    });
  }

  const inputClass =
    "w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-brand-500 text-sm dark:bg-gray-900 dark:text-gray-100";
  const labelClass = "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1";
  const resourceList: { id: string; displayName: string; eid: string }[] = resources?.resources ?? [];

  return (
    <div
      className="fixed inset-0 bg-black/50 z-50 flex items-start justify-center overflow-y-auto py-8"
      onClick={(e) => {
        if (e.target === e.currentTarget) onClose();
      }}
    >
      <div
        ref={panelRef}
        className="bg-white dark:bg-gray-800 rounded-xl shadow-2xl w-full max-w-lg mx-4"
        onKeyDown={(e) => { if (e.key === "Escape") onClose(); }}
      >
        {/* Header */}
        <div className="flex items-center justify-between px-6 py-4 border-b border-gray-200 dark:border-gray-700">
          <h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100">Request Vacation</h2>
          <button
            type="button"
            onClick={onClose}
            className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors text-xl leading-none"
            aria-label="Close"
          >
            &times;
          </button>
        </div>

        <form onSubmit={handleSubmit} className="px-6 py-5 space-y-4">
          {/* Resource */}
          {!initialResourceId && (
            <div>
              <label htmlFor="vac-resource" className={labelClass}>
                Resource <span className="text-red-500">*</span><InfoTooltip content="The employee this vacation request is for." />
              </label>
              <select
                id="vac-resource"
                value={resourceId}
                onChange={(e) => setResourceId(e.target.value)}
                className={inputClass}
                required
              >
                <option value="">Select a resource…</option>
                {resourceList.map((r) => (
                  <option key={r.id} value={r.id}>
                    {r.displayName} ({r.eid})
                  </option>
                ))}
              </select>
            </div>
          )}

          {/* Type */}
          <div>
            <label htmlFor="vac-type" className={labelClass}>
              Type <span className="text-red-500">*</span><InfoTooltip content="ANNUAL = paid leave (deducted from entitlement) · SICK = sick leave · OTHER = special leave. Public holidays come from Holiday Calendars and are excluded automatically." />
            </label>
            <select
              id="vac-type"
              value={type}
              onChange={(e) => setType(e.target.value as VacationType)}
              className={inputClass}
            >
              {REQUESTABLE_VACATION_TYPES.map((t) => (
                <option key={t} value={t}>
                  {VACATION_TYPE_LABELS[t]}
                </option>
              ))}
            </select>
          </div>

          {/* Dates */}
          <div className="grid grid-cols-2 gap-4">
            <div>
              <label htmlFor="vac-start" className={labelClass}>
                Start Date <span className="text-red-500">*</span><InfoTooltip content="First day of leave (inclusive)." />
              </label>
              <DateInput
                id="vac-start"
                value={startDate}
                onChange={setStartDate}
                className={inputClass}
                required
              />
            </div>
            <div>
              <label htmlFor="vac-end" className={labelClass}>
                End Date <span className="text-red-500">*</span><InfoTooltip content="Last day of leave (inclusive)." />
              </label>
              <DateInput
                id="vac-end"
                value={endDate}
                onChange={setEndDate}
                min={startDate}
                className={inputClass}
                required
              />
            </div>
          </div>

          {/* Half-day toggle */}
          <div className="flex items-center gap-4">
            <label className="flex items-center gap-2 cursor-pointer">
              <input
                type="checkbox"
                checked={isHalfDay}
                onChange={(e) => setIsHalfDay(e.target.checked)}
                className="rounded border-gray-300 dark:border-gray-600 text-brand-600 focus:ring-brand-500"
              />
              <span className="text-sm font-medium text-gray-700 dark:text-gray-300">Half day</span><InfoTooltip content="Request only half a day off (morning or afternoon). Counts as 0.5 days against entitlement." />
            </label>
            {isHalfDay && (
              <div className="flex gap-3">
                <label className="flex items-center gap-1.5 cursor-pointer text-sm text-gray-600 dark:text-gray-400">
                  <input
                    type="radio"
                    value="MORNING"
                    checked={halfDayPart === "MORNING"}
                    onChange={() => setHalfDayPart("MORNING")}
                    className="text-brand-600 focus:ring-brand-500"
                  />
                  Morning
                </label>
                <label className="flex items-center gap-1.5 cursor-pointer text-sm text-gray-600 dark:text-gray-400">
                  <input
                    type="radio"
                    value="AFTERNOON"
                    checked={halfDayPart === "AFTERNOON"}
                    onChange={() => setHalfDayPart("AFTERNOON")}
                    className="text-brand-600 focus:ring-brand-500"
                  />
                  Afternoon
                </label>
              </div>
            )}
          </div>

          {/* Conflict warning */}
          {existingVacations && existingVacations.length > 0 && (
            <div className="rounded-lg bg-amber-50 border border-amber-200 px-4 py-3 text-sm text-amber-700">
              <strong>Existing vacation in this period:</strong>
              <ul className="mt-1 space-y-0.5">
                {existingVacations.map((v) => (
                  <li key={v.id}>
                    {VACATION_TYPE_LABELS[v.type as VacationType]} —{" "}
                    {new Date(v.startDate).toLocaleDateString("en-GB")} to{" "}
                    {new Date(v.endDate).toLocaleDateString("en-GB")} ({v.status})
                  </li>
                ))}
              </ul>
            </div>
          )}

          {/* Team overlap warning */}
          {teamOverlap && teamOverlap.length > 0 && (
            <div className="rounded-lg bg-blue-50 border border-blue-200 px-4 py-3 text-sm text-blue-700">
              <strong>Team members off in this period ({teamOverlap.length}):</strong>
              <ul className="mt-1 space-y-0.5">
                {teamOverlap.map((v) => {
                  const r = v.resource as { displayName: string; eid: string } | null;
                  return (
                    <li key={v.id}>
                      {r?.displayName ?? "—"}{" "}
                      <span className="text-blue-500">({new Date(v.startDate).toLocaleDateString("en-GB")} – {new Date(v.endDate).toLocaleDateString("en-GB")})</span>
                    </li>
                  );
                })}
              </ul>
            </div>
          )}

          {!!resourceId && !!startDate && !!endDate && (
            <div
              data-testid="vacation-preview-card"
              className="rounded-lg border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-900"
            >
              <div className="flex items-center justify-between gap-3">
                <strong>Leave preview</strong>
                {previewQuery.isLoading && (
                  <span className="text-xs text-emerald-700">Calculating…</span>
                )}
              </div>

              {previewQuery.data && (
                <div className="mt-2 space-y-2">
                  <div className="grid grid-cols-3 gap-2 text-xs sm:text-sm">
                    <div className="rounded-md bg-white/70 px-3 py-2">
                      <div className="text-emerald-700">Requested</div>
                      <div data-testid="vacation-preview-requested-days" className="font-semibold">
                        {previewQuery.data.requestedDays}
                      </div>
                    </div>
                    <div className="rounded-md bg-white/70 px-3 py-2">
                      <div className="text-emerald-700">Effective</div>
                      <div data-testid="vacation-preview-effective-days" className="font-semibold">
                        {previewQuery.data.effectiveDays}
                      </div>
                    </div>
                    <div className="rounded-md bg-white/70 px-3 py-2">
                      <div className="text-emerald-700">Deducted</div>
                      <div data-testid="vacation-preview-deducted-days" className="font-semibold">
                        {previewQuery.data.deductedDays}
                      </div>
                    </div>
                  </div>

                  {buildHolidayBasisLabel(previewQuery.data).length > 0 && (
                    <div data-testid="vacation-preview-holiday-basis" className="rounded-md bg-white/70 px-3 py-2 text-xs sm:text-sm">
                      <span className="font-medium">Holiday basis:</span>{" "}
                      {buildHolidayBasisLabel(previewQuery.data).join(" / ")}
                    </div>
                  )}

                  {(previewQuery.data.holidayContext.sources.hasCalendarHolidays || previewQuery.data.holidayContext.sources.hasLegacyPublicHolidayEntries) && (
                    <div data-testid="vacation-preview-holiday-sources" className="rounded-md bg-white/70 px-3 py-2 text-xs sm:text-sm">
                      <span className="font-medium">Sources:</span>{" "}
                      {[
                        previewQuery.data.holidayContext.sources.hasCalendarHolidays ? "Holiday Calendar" : null,
                        previewQuery.data.holidayContext.sources.hasLegacyPublicHolidayEntries ? "Legacy public holiday entries" : null,
                      ].filter(Boolean).join(" + ")}
                    </div>
                  )}

                  {previewQuery.data.publicHolidayDates.length > 0 && (
                    <div data-testid="vacation-preview-public-holidays" className="text-xs sm:text-sm">
                      <span className="font-medium">Excluded public holidays:</span>{" "}
                      {previewQuery.data.holidayDetails.map((holiday) => `${holiday.date} (${getHolidaySourceLabel(holiday.source)})`).join(", ")}
                    </div>
                  )}

                  {previewQuery.data.requestedDays !== previewQuery.data.deductedDays && (
                    <div className="text-xs sm:text-sm text-emerald-800">
                      Public holidays in the selected range are excluded from deducted leave days.
                    </div>
                  )}
                </div>
              )}

              {previewQuery.error && (
                <div className="mt-2 text-xs text-red-700">
                  {previewQuery.error.message}
                </div>
              )}
            </div>
          )}

          {/* Note */}
          <div>
            <label htmlFor="vac-note" className={labelClass}>
              Note (optional)
            </label>
            <textarea
              id="vac-note"
              value={note}
              onChange={(e) => setNote(e.target.value)}
              rows={2}
              maxLength={500}
              className={`${inputClass} resize-none`}
              placeholder="Optional reason or description…"
            />
          </div>

          {/* Server error */}
          {serverError && (
            <div className="rounded-lg bg-red-50 border border-red-200 px-4 py-3 text-sm text-red-700">
              {serverError}
            </div>
          )}

          {/* Footer */}
          <div className="flex items-center justify-end gap-3 pt-2">
            <button
              type="button"
              onClick={onClose}
              disabled={isPending}
              className="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 disabled:opacity-50"
            >
              Cancel
            </button>
            <button
              type="submit"
              disabled={isPending}
              className="px-4 py-2 bg-brand-600 text-white rounded-lg hover:bg-brand-700 text-sm font-medium disabled:opacity-50"
            >
              {isPending ? "Submitting…" : "Submit Request"}
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}
