"use client";

import { clsx } from "clsx";
import { createPortal } from "react-dom";
import { useRef, useState, type RefObject } from "react";
import { useAnchoredOverlay } from "~/hooks/useAnchoredOverlay.js";
import { trpc } from "~/lib/trpc/client.js";

export interface TimelineFilters {
  /** Filter to projects that belong to one of the selected clients. */
  clientIds: string[];
  chapters: string[];
  /** Filter to specific resource EIDs */
  eids: string[];
  /** Filter to specific project IDs */
  projectIds: string[];
  showWeekends: boolean;
  zoom: "day" | "week" | "month";
  /**
   * Hide allocations whose project has status COMPLETED or CANCELLED.
   * Defaults to the user's global app preference; can be toggled per session.
   */
  hideCompletedProjects: boolean;
  /** Show DRAFT projects and their PROPOSED allocations on the timeline. */
  showDrafts: boolean;
  /** Show approved vacation blocks on resource rows. Default: true. */
  showVacations: boolean;
  /** Show open-demand entries (no resource assigned yet). Default: true. */
  showPlaceholders: boolean;
  /** Filter to specific country IDs */
  countryCodes: string[];
}

export const DEFAULT_FILTERS: TimelineFilters = {
  clientIds: [],
  chapters: [],
  eids: [],
  projectIds: [],
  countryCodes: [],
  showWeekends: false,
  zoom: "day",
  hideCompletedProjects: true, // overridden at runtime from AppPreferences
  showDrafts: false,
  showVacations: true,
  showPlaceholders: true,
};

interface TimelineFilterProps {
  anchorRef: RefObject<HTMLDivElement | null>;
  filters: TimelineFilters;
  onChange: (filters: TimelineFilters) => void;
  isOpen: boolean;
  onClose: () => void;
}

// ─── Chip ─────────────────────────────────────────────────────────────────────

function Chip({ label, onRemove }: { label: string; onRemove: () => void }) {
  return (
    <span className="inline-flex items-center gap-1 rounded-full border border-brand-200 bg-brand-50 px-2 py-0.5 text-xs font-medium text-brand-700 dark:border-brand-800 dark:bg-brand-950/40 dark:text-brand-200">
      {label}
      <button
        type="button"
        onClick={onRemove}
        className="leading-none text-brand-400 hover:text-brand-700 dark:hover:text-brand-100"
      >
        ×
      </button>
    </span>
  );
}

// ─── Project picker ───────────────────────────────────────────────────────────

function ProjectPicker({
  selectedIds,
  onChange,
}: {
  selectedIds: string[];
  onChange: (ids: string[]) => void;
}) {
  const [search, setSearch] = useState("");
  const [open, setOpen] = useState(false);
  const inputRef = useRef<HTMLInputElement>(null);

  const { data } = trpc.project.list.useQuery({ search, limit: 200 }, { staleTime: 15_000 });
  type ProjectRow = { id: string; shortCode: string; name: string };
  const suggestions = ((data?.projects as ProjectRow[] | undefined) ?? []).filter(
    (p) => !selectedIds.includes(p.id),
  );

  const { data: allData } = trpc.project.list.useQuery({ limit: 500 }, { staleTime: 60_000 });
  const projectMap = new Map(
    ((allData?.projects as ProjectRow[] | undefined) ?? []).map((p) => [p.id, p]),
  );

  function add(id: string) {
    onChange([...selectedIds, id]);
    setSearch("");
    inputRef.current?.focus();
  }

  function remove(id: string) {
    onChange(selectedIds.filter((i) => i !== id));
  }

  return (
    <div>
      <div className="flex flex-wrap gap-1 mb-1.5">
        {selectedIds.map((id) => {
          const project = projectMap.get(id);
          return <Chip key={id} label={project ? project.name : id} onRemove={() => remove(id)} />;
        })}
      </div>
      <div className="relative">
        <input
          ref={inputRef}
          type="text"
          placeholder="Search projects…"
          value={search}
          onChange={(e) => {
            setSearch(e.target.value);
            setOpen(true);
          }}
          onFocus={() => setOpen(true)}
          onBlur={() => setTimeout(() => setOpen(false), 150)}
          className="app-input px-2.5 py-1.5 text-xs"
        />
        {open && suggestions.length > 0 && (
          <div
            className="absolute left-0 right-0 top-full z-50 mt-1 max-h-40 overflow-y-auto rounded-xl border border-gray-200 bg-white shadow-lg dark:border-gray-700 dark:bg-gray-900"
            onMouseDown={(e) => e.preventDefault()}
          >
            {suggestions.map((project) => (
              <button
                key={project.id}
                type="button"
                onMouseDown={(e) => {
                  e.preventDefault();
                  add(project.id);
                }}
                className="flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs hover:bg-gray-50 dark:hover:bg-gray-800"
              >
                <span className="truncate text-gray-800 dark:text-gray-100">{project.name}</span>
              </button>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

// ─── Main filter panel ────────────────────────────────────────────────────────

export function TimelineFilter({
  anchorRef,
  filters,
  onChange,
  isOpen,
  onClose,
}: TimelineFilterProps) {
  const { panelRef, position } = useAnchoredOverlay<HTMLDivElement>({
    open: isOpen,
    onClose,
    align: "end",
    triggerRef: anchorRef,
  });

  if (!isOpen) return null;

  const activeCount =
    filters.clientIds.length +
    filters.chapters.length +
    filters.eids.length +
    filters.projectIds.length +
    filters.countryCodes.length;

  return createPortal(
    <div
      ref={panelRef}
      style={{ position: "fixed", top: position.top, left: position.left }}
      className="z-[9998] w-80 rounded-2xl border border-gray-200 bg-white p-4 shadow-xl dark:border-gray-700 dark:bg-gray-900"
    >
      <div className="mb-4 flex items-center justify-between">
        <h3 className="font-semibold text-gray-900 dark:text-gray-100">
          Filters
          {activeCount > 0 && (
            <span className="ml-2 text-xs font-normal text-brand-600 dark:text-brand-300">
              {activeCount} active
            </span>
          )}
        </h3>
        <button
          type="button"
          onClick={onClose}
          className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-200"
        >
          ✕
        </button>
      </div>

      {/* Zoom level */}
      <div className="mb-5">
        <label className="mb-2 block text-xs font-medium uppercase tracking-wider text-gray-500">
          Zoom
        </label>
        <div className="flex gap-2">
          {(["day", "week", "month"] as const).map((z) => (
            <button
              type="button"
              key={z}
              onClick={() => onChange({ ...filters, zoom: z })}
              className={clsx(
                "flex-1 rounded-xl border px-2 py-1.5 text-xs capitalize transition-colors",
                filters.zoom === z
                  ? "border-brand-300 bg-brand-50 text-brand-700 dark:border-brand-700 dark:bg-brand-950/40 dark:text-brand-200"
                  : "border-gray-300 text-gray-600 hover:bg-gray-50 dark:border-gray-600 dark:text-gray-300 dark:hover:bg-gray-800",
              )}
            >
              {z}
            </button>
          ))}
        </div>
      </div>

      {/* Project filter */}
      <div className="mb-5">
        <label className="mb-2 block text-xs font-medium uppercase tracking-wider text-gray-500">
          Projects
        </label>
        <ProjectPicker
          selectedIds={filters.projectIds}
          onChange={(projectIds) => onChange({ ...filters, projectIds })}
        />
      </div>

      {/* Visibility toggles */}
      <div className="mb-4 space-y-2">
        <label className="mb-2 block text-xs font-medium uppercase tracking-wider text-gray-500">
          Visibility
        </label>
        <label className="flex cursor-pointer items-center gap-2 rounded-lg px-2 py-1 text-sm hover:bg-gray-50 dark:hover:bg-gray-800">
          <input
            type="checkbox"
            checked={filters.showWeekends}
            onChange={(e) => onChange({ ...filters, showWeekends: e.target.checked })}
            className="rounded border-gray-300 dark:border-gray-600"
          />
          <span className="text-gray-700 dark:text-gray-300">Show weekends</span>
        </label>
        <label className="flex cursor-pointer items-start gap-2 rounded-lg px-2 py-1 text-sm hover:bg-gray-50 dark:hover:bg-gray-800">
          <input
            type="checkbox"
            checked={!filters.hideCompletedProjects}
            onChange={(e) => onChange({ ...filters, hideCompletedProjects: !e.target.checked })}
            className="mt-0.5 rounded border-gray-300 dark:border-gray-600"
          />
          <span className="text-gray-700 dark:text-gray-300">
            Show completed &amp; cancelled
            <span className="block text-xs text-gray-400 font-normal">
              Default set in Preferences
            </span>
          </span>
        </label>
        <label className="flex cursor-pointer items-start gap-2 rounded-lg px-2 py-1 text-sm hover:bg-gray-50 dark:hover:bg-gray-800">
          <input
            type="checkbox"
            checked={filters.showDrafts}
            onChange={(e) => onChange({ ...filters, showDrafts: e.target.checked })}
            className="mt-0.5 rounded border-gray-300 dark:border-gray-600"
          />
          <span className="text-gray-700 dark:text-gray-300">
            Show draft projects
            <span className="block text-xs text-gray-400 font-normal">
              Shows PROPOSED allocations
            </span>
          </span>
        </label>
        <label className="flex cursor-pointer items-start gap-2 rounded-lg px-2 py-1 text-sm hover:bg-gray-50 dark:hover:bg-gray-800">
          <input
            type="checkbox"
            checked={filters.showVacations}
            onChange={(e) => onChange({ ...filters, showVacations: e.target.checked })}
            className="mt-0.5 rounded border-gray-300 dark:border-gray-600"
          />
          <span className="text-gray-700 dark:text-gray-300">
            Show vacation blocks
            <span className="block text-xs text-gray-400 font-normal">
              Approved leave on resource rows
            </span>
          </span>
        </label>
        <label className="flex cursor-pointer items-start gap-2 rounded-lg px-2 py-1 text-sm hover:bg-gray-50 dark:hover:bg-gray-800">
          <input
            type="checkbox"
            checked={filters.showPlaceholders}
            onChange={(e) => onChange({ ...filters, showPlaceholders: e.target.checked })}
            className="mt-0.5 rounded border-gray-300 dark:border-gray-600"
          />
          <span className="text-gray-700 dark:text-gray-300">
            Show open demand
            <span className="block text-xs text-gray-400 font-normal">
              Dashed bars for unassigned staffing demand
            </span>
          </span>
        </label>
      </div>

      <button
        type="button"
        onClick={() => onChange(DEFAULT_FILTERS)}
        disabled={
          activeCount === 0 &&
          !filters.showWeekends &&
          filters.hideCompletedProjects &&
          !filters.showDrafts &&
          filters.showVacations &&
          filters.showPlaceholders
        }
        className="w-full text-xs text-gray-500 underline transition hover:text-gray-700 disabled:no-underline disabled:opacity-40 dark:text-gray-400 dark:hover:text-gray-200"
      >
        Reset all filters
      </button>
    </div>,
    document.body,
  );
}
