'use client';

import { X, Filter, ChevronDown } from 'lucide-react';

import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { DatePicker } from '@/components/ui/date-picker';
import { Badge } from '@/components/ui/badge';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { Checkbox } from '@/components/ui/checkbox';
import { Label } from '@/components/ui/label';
import { CountryCombobox } from '@/components/shared/country-combobox';
import { CurrencySelect } from '@/components/shared/currency-select';
import type { CountryCode } from '@/lib/i18n/countries';

export type FilterType =
  | 'text'
  | 'select'
  | 'multi-select'
  | 'date-range'
  | 'date'
  | 'boolean'
  | 'relation'
  | 'currency'
  | 'country';

export interface FilterOption {
  label: string;
  value: string;
}

export interface FilterDefinition {
  key: string;
  label: string;
  type: FilterType;
  options?: FilterOption[];
  placeholder?: string;
}

export type FilterValues = Record<string, unknown>;

interface FilterBarProps {
  filters: FilterDefinition[];
  values: FilterValues;
  onChange: (key: string, value: unknown) => void;
  onClear: () => void;
}

/**
 * Serializes filter values to URL search params.
 */
export function serializeFiltersToParams(values: FilterValues): URLSearchParams {
  const params = new URLSearchParams();
  for (const [key, value] of Object.entries(values)) {
    if (value === undefined || value === null || value === '') continue;
    if (Array.isArray(value)) {
      if (value.length > 0) params.set(key, value.join(','));
    } else {
      params.set(key, String(value));
    }
  }
  return params;
}

/**
 * Deserializes URL search params into filter values.
 */
export function deserializeFiltersFromParams(
  params: URLSearchParams,
  definitions: FilterDefinition[],
): FilterValues {
  const values: FilterValues = {};
  for (const def of definitions) {
    const raw = params.get(def.key);
    if (!raw) continue;
    if (def.type === 'multi-select' || def.type === 'relation') {
      // `relation` types (e.g. tag-pickers rendered outside the FilterBar)
      // also serialize as comma-joined arrays so the URL round-trips.
      values[def.key] = raw.split(',');
    } else if (def.type === 'boolean') {
      values[def.key] = raw === 'true';
    } else {
      values[def.key] = raw;
    }
  }
  return values;
}

function getActiveFilterCount(values: FilterValues): number {
  let count = 0;
  for (const value of Object.values(values)) {
    if (value === undefined || value === null || value === '') continue;
    if (Array.isArray(value) && value.length === 0) continue;
    count++;
  }
  return count;
}

export function FilterBar({ filters, values, onChange, onClear }: FilterBarProps) {
  const activeCount = getActiveFilterCount(values);

  return (
    <div className="flex items-center gap-2 flex-wrap">
      <Popover>
        <PopoverTrigger asChild>
          <Button variant="outline" size="sm" className="h-8">
            <Filter className="mr-1.5 h-3.5 w-3.5" aria-hidden />
            Filters
            {activeCount > 0 && (
              <Badge variant="secondary" className="ml-1.5 px-1.5 py-0 text-xs">
                {activeCount}
              </Badge>
            )}
            <ChevronDown className="ml-1 h-3.5 w-3.5" aria-hidden />
          </Button>
        </PopoverTrigger>
        <PopoverContent className="w-80 p-4" align="start">
          <div className="space-y-4">
            <div className="flex items-center justify-between">
              <h4 className="text-sm font-medium">Filters</h4>
              {activeCount > 0 && (
                <Button variant="ghost" size="sm" className="h-7 text-xs" onClick={onClear}>
                  Clear all
                </Button>
              )}
            </div>
            {filters.map((filter) => (
              <FilterField
                key={filter.key}
                definition={filter}
                value={values[filter.key]}
                onChange={(val) => onChange(filter.key, val)}
              />
            ))}
          </div>
        </PopoverContent>
      </Popover>

      {/* Active filter chips */}
      {activeCount > 0 &&
        filters.map((filter) => {
          const value = values[filter.key];
          if (value === undefined || value === null || value === '') return null;
          if (Array.isArray(value) && value.length === 0) return null;

          const displayValue = Array.isArray(value)
            ? `${value.length} selected`
            : typeof value === 'boolean'
              ? value
                ? 'Yes'
                : 'No'
              : (filter.options?.find((o) => o.value === String(value))?.label ?? String(value));

          return (
            <Badge key={filter.key} variant="secondary" className="h-7 gap-1 px-2 font-normal">
              {filter.label}: {displayValue}
              <button
                className="ml-1 rounded-full hover:bg-muted-foreground/20"
                onClick={() => onChange(filter.key, undefined)}
              >
                <X className="h-3 w-3" />
              </button>
            </Badge>
          );
        })}
    </div>
  );
}

function FilterField({
  definition,
  value,
  onChange,
}: {
  definition: FilterDefinition;
  value: unknown;
  onChange: (value: unknown) => void;
}) {
  switch (definition.type) {
    case 'text':
      return (
        <div className="space-y-1">
          <Label className="text-xs">{definition.label}</Label>
          <Input
            placeholder={definition.placeholder ?? `Filter by ${definition.label.toLowerCase()}...`}
            value={(value as string) ?? ''}
            onChange={(e) => onChange(e.target.value || undefined)}
            className="h-8"
          />
        </div>
      );

    case 'select': {
      // Radix Select forbids empty-string item values (throws at render
      // time, crashes the page). Use a sentinel and translate.
      const ANY = '__any__';
      // Hide the field entirely when there's nothing to pick - avoids a
      // bare "Status" / "Stage" label sitting above an empty dropdown
      // before the parent has loaded options.
      if (!definition.options || definition.options.length === 0) return null;
      return (
        <div className="space-y-1">
          <Label className="text-xs">{definition.label}</Label>
          <Select
            value={(value as string) || ANY}
            onValueChange={(v) => onChange(v === ANY ? undefined : v)}
          >
            <SelectTrigger className="h-8">
              <SelectValue placeholder={definition.placeholder ?? 'Any'} />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value={ANY}>Any</SelectItem>
              {definition.options?.map((opt) => (
                <SelectItem key={opt.value} value={opt.value}>
                  {opt.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
      );
    }

    case 'multi-select': {
      // Hide the entire field - label + checkbox list - when there's
      // nothing to filter by. Tags/segments/etc. that aren't configured
      // yet would otherwise show as a "Tags" header with an empty box
      // beneath it.
      if (!definition.options || definition.options.length === 0) return null;
      return (
        <div className="space-y-2">
          <Label className="text-xs">{definition.label}</Label>
          <div className="max-h-32 overflow-y-auto space-y-1">
            {definition.options.map((opt) => {
              const selected = Array.isArray(value) ? value.includes(opt.value) : false;
              return (
                <div key={opt.value} className="flex items-center gap-2">
                  <Checkbox
                    id={`${definition.key}-${opt.value}`}
                    checked={selected}
                    onCheckedChange={(checked) => {
                      const current: string[] = Array.isArray(value)
                        ? value.filter((v): v is string => typeof v === 'string')
                        : [];
                      const next = checked
                        ? [...current, opt.value]
                        : current.filter((v) => v !== opt.value);
                      onChange(next.length > 0 ? next : undefined);
                    }}
                  />
                  <label
                    htmlFor={`${definition.key}-${opt.value}`}
                    className="text-sm cursor-pointer"
                  >
                    {opt.label}
                  </label>
                </div>
              );
            })}
          </div>
        </div>
      );
    }

    case 'date':
      return (
        <div className="space-y-1">
          <Label className="text-xs">{definition.label}</Label>
          <DatePicker
            value={(value as string) ?? ''}
            onChange={(v) => onChange(v || undefined)}
            className="h-8"
          />
        </div>
      );

    case 'currency':
      return (
        <div className="space-y-1">
          <Label className="text-xs">{definition.label}</Label>
          <CurrencySelect
            value={(value as string) ?? undefined}
            onValueChange={(v) => onChange(v || undefined)}
            className="h-8"
          />
        </div>
      );

    case 'country':
      return (
        <div className="space-y-1">
          <Label className="text-xs">{definition.label}</Label>
          <CountryCombobox
            value={(value as CountryCode | null) ?? null}
            onChange={(c) => onChange(c ?? undefined)}
            clearable
          />
        </div>
      );

    case 'boolean':
      return (
        <div className="flex items-center gap-2">
          <Checkbox
            id={definition.key}
            checked={value === true}
            onCheckedChange={(checked) => onChange(checked || undefined)}
          />
          <label htmlFor={definition.key} className="text-sm cursor-pointer">
            {definition.label}
          </label>
        </div>
      );

    default:
      return null;
  }
}
