"use client";

import * as React from "react";
import { Filter } from "lucide-react";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Slider } from "@/components/ui/slider";
import { Spinner } from "@/components/ui/spinner";

export type CompactFilterOption = {
  value: string;
  label: React.ReactNode;
};

type CompactFilterSectionBase = {
  id: string;
  label: string;
  disabled?: boolean;
  loading?: boolean;
  /** When set, consecutive sections with the same group show one shared heading in the nav. */
  group?: string;
};

type CompactFilterListSectionBase = CompactFilterSectionBase & {
  options: CompactFilterOption[];
  /** Treated as "no filter" for active badge and clearing a selection (default: `"all"`). */
  inactiveValue?: string | "all";
};

export type CompactFilterRangeSection = CompactFilterSectionBase & {
  kind: "range";
  min: number | null;
  max: number | null;
  onRangeChange: (range: { min: number | null; max: number | null }) => void;
  sliderMin?: number;
  sliderMax?: number;
  sliderStep?: number;
};

export type CompactFilterSection = CompactFilterListSectionBase &
  (
    | {
        multi?: false;
        value: string | "all";
        onValueChange: (value: string | "all") => void;
      }
    | {
        multi: true;
        values: string[];
        onValuesChange: (values: string[]) => void;
      }
  ) | CompactFilterRangeSection;

const DEFAULT_RANGE_MIN = 0;
const DEFAULT_RANGE_MAX = 1_000_000;
const DEFAULT_RANGE_STEP = 5_000;

export function isCompactFilterRangeSection(
  section: CompactFilterSection,
): section is CompactFilterRangeSection {
  return "kind" in section && section.kind === "range";
}

export function compactFilterSectionIsActive(section: CompactFilterSection): boolean {
  if (isCompactFilterRangeSection(section)) {
    return (
      (section.min != null && Number.isFinite(section.min)) ||
      (section.max != null && Number.isFinite(section.max))
    );
  }
  if (section.multi) return section.values.length > 0;
  const inactive = section.inactiveValue ?? "all";
  return section.value !== inactive;
}

export function formatCompactFilterCurrency(n: number): string {
  if (n >= 1_000_000) return `$${(n / 1_000_000).toFixed(1)}M`;
  if (n >= 1_000) return `$${Math.round(n / 1_000)}k`;
  return `$${n.toLocaleString()}`;
}

function CompactFilterRangePanel({
  section,
}: {
  section: CompactFilterRangeSection;
}) {
  const sliderMin = section.sliderMin ?? DEFAULT_RANGE_MIN;
  const sliderMax = section.sliderMax ?? DEFAULT_RANGE_MAX;
  const sliderStep = section.sliderStep ?? DEFAULT_RANGE_STEP;

  const sliderValue = React.useMemo((): [number, number] => {
    const lo = section.min ?? sliderMin;
    const hi = section.max ?? sliderMax;
    return [lo, hi];
  }, [section.min, section.max, sliderMin, sliderMax]);

  const handleSliderChange = React.useCallback(
    (vals: number[]) => {
      const [lo, hi] = vals;
      section.onRangeChange({
        min: lo <= sliderMin ? null : lo,
        max: hi >= sliderMax ? null : hi,
      });
    },
    [section, sliderMin, sliderMax],
  );

  const handleClear = React.useCallback(() => {
    section.onRangeChange({ min: null, max: null });
  }, [section]);

  return (
    <div className="pr-2">
      <div className="flex justify-between text-[11px] font-bold text-gray-600 font-['Lexend_Deca'] mb-2">
        <span>{formatCompactFilterCurrency(sliderValue[0])}</span>
        <span>{formatCompactFilterCurrency(sliderValue[1])}</span>
      </div>
      <Slider
        min={sliderMin}
        max={sliderMax}
        step={sliderStep}
        value={sliderValue}
        onValueChange={handleSliderChange}
        disabled={section.disabled}
        className="mb-4"
      />
      <Button
        type="button"
        variant="ghost"
        size="sm"
        className="h-8 w-full text-[12px] font-bold rounded-lg"
        onClick={handleClear}
        disabled={section.disabled || !compactFilterSectionIsActive(section)}
      >
        Clear range
      </Button>
    </div>
  );
}

type CompactFilterPopoverProps = {
  sections: CompactFilterSection[];
  triggerClassName?: string;
  contentClassName?: string;
  ariaLabel?: string;
};

export function CompactFilterPopover({
  sections,
  triggerClassName,
  contentClassName,
  ariaLabel = "Filters",
}: CompactFilterPopoverProps) {
  const [open, setOpen] = React.useState(false);
  const [activeSectionId, setActiveSectionId] = React.useState(
    () => sections[0]?.id ?? "",
  );

  React.useEffect(() => {
    if (!sections.some((section) => section.id === activeSectionId)) {
      setActiveSectionId(sections[0]?.id ?? "");
    }
  }, [sections, activeSectionId]);

  const activeCount = sections.filter(compactFilterSectionIsActive).length;
  const activeSection = sections.find((section) => section.id === activeSectionId) ?? sections[0];

  if (sections.length === 0) return null;

  return (
    <Popover open={open} onOpenChange={setOpen}>
      <PopoverTrigger asChild>
        <Button
          type="button"
          variant="outline"
          size="icon-xs"
          className={cn(
            "relative",
            triggerClassName,
            activeCount > 0 &&
              "border-accent/40 text-accent bg-accent/5 ring-1 ring-accent/20",
          )}
          aria-label={
            activeCount > 0 ? `${ariaLabel} (${activeCount} active)` : ariaLabel
          }
        >
          <Filter className="size-4" aria-hidden />
          {activeCount > 0 ? (
            <span className="absolute -right-0.5 -top-0.5 flex size-4 items-center justify-center rounded-full bg-accent text-[9px] font-bold leading-none text-white">
              {activeCount}
            </span>
          ) : null}
        </Button>
      </PopoverTrigger>
      <PopoverContent
        align="end"
        className={cn(
          "w-[min(100vw-2rem,22rem)] rounded-2xl border-border/40 p-0 shadow-premium",
          contentClassName,
        )}
      >
        <div className="flex max-h-[min(70vh,420px)] min-h-[280px] flex-col sm:flex-row">
          <div className="shrink-0 border-b border-border/40 p-2 sm:w-36 sm:border-b-0 sm:border-r">
            <p className="px-2 pb-1 font-['Lexend_Deca'] text-[10px] font-bold uppercase tracking-widest text-gray-400">
              Filter by
            </p>
            <ScrollArea className="max-h-32 sm:max-h-none">
              <ul className="flex gap-0.5 overflow-x-auto sm:flex-col sm:overflow-x-visible">
                {sections.map((section, index) => {
                  const isActive = section.id === activeSectionId;
                  const hasValue = compactFilterSectionIsActive(section);
                  const prevGroup = sections[index - 1]?.group;
                  const showGroupHeader =
                    Boolean(section.group) && section.group !== prevGroup;
                  return (
                    <li key={section.id}>
                      {showGroupHeader ? (
                        <p className="px-2 pb-0.5 pt-2 font-['Lexend_Deca'] text-[9px] font-bold uppercase tracking-wide text-gray-400 first:pt-0">
                          {section.group}
                        </p>
                      ) : null}
                      <button
                        type="button"
                        onClick={() => setActiveSectionId(section.id)}
                        className={cn(
                          "w-full whitespace-nowrap rounded-lg py-1.5 text-left font-['Lexend_Deca'] text-[12px] font-semibold transition-colors sm:whitespace-normal",
                          section.group ? "pl-4 pr-2.5" : "px-2.5",
                          isActive
                            ? "bg-accent/10 text-accent"
                            : "text-gray-600 hover:bg-gray-50",
                        )}
                      >
                        <span className="flex items-center gap-1.5">
                          {section.label}
                          {hasValue ? (
                            <span
                              className="size-1.5 shrink-0 rounded-full bg-accent"
                              aria-hidden
                            />
                          ) : null}
                        </span>
                      </button>
                    </li>
                  );
                })}
              </ul>
            </ScrollArea>
          </div>

          <div className="flex min-h-0 min-w-0 flex-1 flex-col p-3">
            {activeSection?.group ? (
              <p className="mb-0.5 font-['Lexend_Deca'] text-[9px] font-bold uppercase tracking-wide text-gray-400">
                {activeSection.group}
              </p>
            ) : null}
            <p className="mb-2 font-['Lexend_Deca'] text-[11px] font-bold text-gray-700">
              {activeSection?.label}
            </p>
            {activeSection?.loading ? (
              <div className="flex flex-1 items-center justify-center py-8">
                <Spinner className="size-5" />
              </div>
            ) : isCompactFilterRangeSection(activeSection) ? (
              <CompactFilterRangePanel section={activeSection} />
            ) : (
              <ScrollArea className="min-h-0 flex-1">
                <ul className="space-y-1 pr-2">
                  {activeSection?.multi
                    ? activeSection.options.map((option) => {
                        const checked = activeSection.values.includes(option.value);
                        const disabled = activeSection.disabled;
                        const optionId = `${activeSection.id}-${option.value}`;
                        return (
                          <li key={option.value}>
                            <label
                              htmlFor={optionId}
                              className={cn(
                                "flex cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1.5 text-[12px] font-medium hover:bg-gray-50",
                                disabled && "cursor-not-allowed opacity-50",
                              )}
                            >
                              <Checkbox
                                id={optionId}
                                checked={checked}
                                disabled={disabled}
                                onCheckedChange={() => {
                                  if (disabled) return;
                                  const next = checked
                                    ? activeSection.values.filter((v) => v !== option.value)
                                    : [...activeSection.values, option.value];
                                  activeSection.onValuesChange(next);
                                }}
                              />
                              <span className="truncate">{option.label}</span>
                            </label>
                          </li>
                        );
                      })
                    : activeSection?.options.map((option) => {
                        const checked = activeSection.value === option.value;
                        const disabled = activeSection.disabled;
                        const optionId = `${activeSection.id}-${option.value}`;
                        return (
                          <li key={option.value}>
                            <label
                              htmlFor={optionId}
                              className={cn(
                                "flex cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1.5 text-[12px] font-medium hover:bg-gray-50",
                                disabled && "cursor-not-allowed opacity-50",
                              )}
                            >
                              <Checkbox
                                id={optionId}
                                checked={checked}
                                disabled={disabled}
                                onCheckedChange={() => {
                                  if (disabled) return;
                                  const inactive =
                                    activeSection.inactiveValue ?? "all";
                                  const next =
                                    checked && option.value !== inactive
                                      ? inactive
                                      : (option.value as string | "all");
                                  activeSection.onValueChange(next);
                                }}
                              />
                              <span className="truncate">{option.label}</span>
                            </label>
                          </li>
                        );
                      })}
                </ul>
              </ScrollArea>
            )}
          </div>
        </div>
      </PopoverContent>
    </Popover>
  );
}
