"use client";

import Link from "next/link";
import { useRouter, usePathname, useSearchParams } from "next/navigation";
import { useTranslations } from "next-intl";
import { ArrowRight } from "lucide-react";
import { Checkbox } from "@/components/ui/checkbox";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { Label } from "@/components/ui/label";
import { Separator } from "@/components/ui/separator";
import { Slider } from "@/components/ui/slider";
import { Input } from "@/components/ui/input";
import { type Locale } from "@/config/i18n.config";
import { useState, useCallback, useEffect, useMemo } from "react";
import type { StorefrontProductPriceRange } from "@/lib/products/storefront-product-filters";

export interface FilterItem {
  name: string;
  slug: string;
}

export interface ProductFiltersProps {
  locale: Locale;
  categories: FilterItem[];
  collections: FilterItem[];
  currentCategory?: string;
  currentCollection?: string;
  currentMinPrice?: string;
  currentMaxPrice?: string;
  currentSort?: string;
  /**
   * Real price bounds of the products in scope. Falls back to the legacy
   * $0–1000 span only when the caller has no range to give.
   */
  priceRange?: StorefrontProductPriceRange | null;
  /**
   * Set false where sorting lives in a toolbar above the grid instead — sort is
   * not a filter, and users look for it next to the result count.
   */
  showSort?: boolean;
}

export const FALLBACK_PRICE_RANGE: StorefrontProductPriceRange = {
  min: 0,
  max: 1000,
  step: 10,
};
const CATEGORY_VISIBLE_LIMIT = 10;

/**
 * Show a filter group as soon as it has any option.
 *
 * A single-option group cannot narrow the current result set, but it still tells
 * a shopper what the store sells, and it is the control they look for when more
 * products arrive — so it stays visible.
 */
const MIN_USEFUL_OPTIONS = 1;

export function resolvePriceBounds(
  priceRange?: StorefrontProductPriceRange | null,
): StorefrontProductPriceRange {
  if (!priceRange) return FALLBACK_PRICE_RANGE;
  const step = priceRange.step > 0 ? priceRange.step : 1;
  return { min: priceRange.min, max: priceRange.max, step };
}

export function ProductFilters({
  locale,
  categories,
  collections,
  currentCategory,
  currentCollection,
  currentMinPrice,
  currentMaxPrice,
  currentSort = "popular",
  priceRange,
  showSort = true,
}: ProductFiltersProps) {
  const t = useTranslations();
  const router = useRouter();
  const pathname = usePathname();
  const searchParams = useSearchParams();

  // Parse comma-separated values from URL
  const selectedCategories = useMemo(
    () => (currentCategory ? currentCategory.split(",") : []),
    [currentCategory]
  );
  const selectedCollections = useMemo(
    () => (currentCollection ? currentCollection.split(",") : []),
    [currentCollection]
  );

  const bounds = useMemo(() => resolvePriceBounds(priceRange), [priceRange]);
  // Every product shares one price — the slider would be a dead control.
  const showPriceFilter = bounds.max > bounds.min;

  const clampPrice = useCallback(
    (value: number) => Math.min(bounds.max, Math.max(bounds.min, value)),
    [bounds.max, bounds.min]
  );

  const [priceValues, setPriceValues] = useState<[number, number]>([
    currentMinPrice ? clampPrice(parseInt(currentMinPrice)) : bounds.min,
    currentMaxPrice ? clampPrice(parseInt(currentMaxPrice)) : bounds.max,
  ]);

  // The URL is the source of truth: re-sync after navigation, and after the
  // bounds themselves change (a different vendor's store has a different span).
  useEffect(() => {
    setPriceValues([
      currentMinPrice ? clampPrice(parseInt(currentMinPrice)) : bounds.min,
      currentMaxPrice ? clampPrice(parseInt(currentMaxPrice)) : bounds.max,
    ]);
  }, [currentMinPrice, currentMaxPrice, bounds.min, bounds.max, clampPrice]);

  const visibleCategories = useMemo(
    () => categories.slice(0, CATEGORY_VISIBLE_LIMIT),
    [categories]
  );
  const hasMoreCategories = categories.length > CATEGORY_VISIBLE_LIMIT;
  const showCategories = categories.length >= MIN_USEFUL_OPTIONS;
  const showCollections = collections.length >= MIN_USEFUL_OPTIONS;

  const updateFilters = useCallback(
    (updates: Record<string, string | undefined>) => {
      const params = new URLSearchParams(searchParams.toString());

      Object.entries(updates).forEach(([key, value]) => {
        if (value) {
          params.set(key, value);
        } else {
          params.delete(key);
        }
      });

      // Reset to page 1 when filters change
      params.delete("page");

      router.push(`${pathname}?${params.toString()}`);
    },
    [pathname, router, searchParams]
  );

  // Toggle checkbox in a comma-separated list
  const toggleFilter = useCallback(
    (key: string, value: string, currentValues: string[]) => {
      const newValues = currentValues.includes(value)
        ? currentValues.filter((v) => v !== value)
        : [...currentValues, value];

      updateFilters({
        [key]: newValues.length > 0 ? newValues.join(",") : undefined,
      });
    },
    [updateFilters]
  );

  const handleSortChange = (value: string) => {
    updateFilters({ sortBy: value });
  };

  // A bound left at its edge is not a filter, so it is dropped from the URL
  // rather than pinned there as a no-op query param.
  const commitPrice = useCallback(
    (min: number, max: number) => {
      updateFilters({
        minPrice: min > bounds.min ? min.toString() : undefined,
        maxPrice: max < bounds.max ? max.toString() : undefined,
      });
    },
    [bounds.max, bounds.min, updateFilters]
  );

  const handlePriceChange = (values: number[]) => {
    setPriceValues([values[0], values[1]]);
  };

  const handlePriceCommit = (values: number[]) => {
    setPriceValues([values[0], values[1]]);
    commitPrice(values[0], values[1]);
  };

  const handleMinPriceInput = (e: React.ChangeEvent<HTMLInputElement>) => {
    const parsed = parseInt(e.target.value);
    const next = Math.min(
      priceValues[1],
      clampPrice(Number.isNaN(parsed) ? bounds.min : parsed)
    );
    setPriceValues([next, priceValues[1]]);
    commitPrice(next, priceValues[1]);
  };

  const handleMaxPriceInput = (e: React.ChangeEvent<HTMLInputElement>) => {
    const parsed = parseInt(e.target.value);
    const next = Math.max(
      priceValues[0],
      clampPrice(Number.isNaN(parsed) ? bounds.max : parsed)
    );
    setPriceValues([priceValues[0], next]);
    commitPrice(priceValues[0], next);
  };

  return (
    <div className="space-y-6">
      {/* Price. Separators lead each following group rather than trailing it, so
          hiding any group can never leave a dangling rule behind. */}
      {showPriceFilter && (
          <div className="space-y-4">
            <h3 className="text-sm font-bold tracking-wide">
              {t("common.price")}
            </h3>

            <Slider
              min={bounds.min}
              max={bounds.max}
              step={bounds.step}
              value={priceValues}
              onValueChange={handlePriceChange}
              onValueCommit={handlePriceCommit}
            />

            <div className="grid grid-cols-2 gap-3">
              <div className="space-y-1">
                <Label className="text-xs text-muted-foreground">
                  {t("productsPage.filters.minPrice")}
                </Label>
                <div className="relative">
                  <span className="absolute left-3 top-1/2 -translate-y-1/2 text-sm text-muted-foreground">
                    $
                  </span>
                  <Input
                    type="number"
                    min={bounds.min}
                    max={priceValues[1]}
                    value={priceValues[0]}
                    onChange={handleMinPriceInput}
                    className="pl-7 h-9"
                  />
                </div>
              </div>
              <div className="space-y-1">
                <Label className="text-xs text-muted-foreground">
                  {t("productsPage.filters.maxPrice")}
                </Label>
                <div className="relative">
                  <span className="absolute left-3 top-1/2 -translate-y-1/2 text-sm text-muted-foreground">
                    $
                  </span>
                  <Input
                    type="number"
                    min={priceValues[0]}
                    max={bounds.max}
                    value={priceValues[1]}
                    onChange={handleMaxPriceInput}
                    className="pl-7 h-9"
                  />
                </div>
              </div>
            </div>
          </div>
      )}

      {/* Categories */}
      {showCategories && (
        <>
          {showPriceFilter ? <Separator /> : null}
          <div className="space-y-3">
            <h3 className="text-sm font-bold tracking-wide">
              {t("common.categories")}
            </h3>
            <div className="space-y-2.5">
              {visibleCategories.map((cat) => (
                <label
                  key={cat.slug}
                  className="flex items-center gap-2.5 cursor-pointer"
                >
                  <Checkbox
                    checked={selectedCategories.includes(cat.slug)}
                    onCheckedChange={() =>
                      toggleFilter("category", cat.slug, selectedCategories)
                    }
                  />
                  <span className="text-sm">{cat.name}</span>
                </label>
              ))}
              {hasMoreCategories ? (
                <Link
                  href={`/${locale}/categories`}
                  className="inline-flex items-center gap-1.5 pt-1 text-sm font-medium text-primary transition-colors hover:text-primary/80"
                >
                  {t("common.viewAll")}
                  <ArrowRight className="h-3.5 w-3.5" aria-hidden="true" />
                </Link>
              ) : null}
            </div>
          </div>
        </>
      )}

      {/* Collections */}
      {showCollections && (
        <>
          {showPriceFilter || showCategories ? <Separator /> : null}
          <div className="space-y-3">
            <h3 className="text-sm font-bold tracking-wide">
              {t("nav.collections")}
            </h3>
            <div className="space-y-2.5">
              {collections.map((col) => (
                <label
                  key={col.slug}
                  className="flex items-center gap-2.5 cursor-pointer"
                >
                  <Checkbox
                    checked={selectedCollections.includes(col.slug)}
                    onCheckedChange={() =>
                      toggleFilter("collection", col.slug, selectedCollections)
                    }
                  />
                  <span className="text-sm">{col.name}</span>
                </label>
              ))}
            </div>
          </div>
        </>
      )}

      {/* Sort By */}
      {showSort && (
        <>
          {showPriceFilter || showCategories || showCollections ? (
            <Separator />
          ) : null}
      <div className="space-y-3">
        <h3 className="text-sm font-bold tracking-wide">
          {t("product.sortBy")}
        </h3>
        <RadioGroup value={currentSort} onValueChange={handleSortChange}>
          <label className="flex items-center gap-2.5 cursor-pointer">
            <RadioGroupItem value="popular" />
            <span className="text-sm">
              {t("productsPage.filters.sortOptions.mostPopular")}
            </span>
          </label>
          <label className="flex items-center gap-2.5 cursor-pointer">
            <RadioGroupItem value="rating" />
            <span className="text-sm">
              {t("productsPage.filters.sortOptions.bestRating")}
            </span>
          </label>
          <label className="flex items-center gap-2.5 cursor-pointer">
            <RadioGroupItem value="createdAt" />
            <span className="text-sm">
              {t("productsPage.filters.sortOptions.newest")}
            </span>
          </label>
          <label className="flex items-center gap-2.5 cursor-pointer">
            <RadioGroupItem value="price-asc" />
            <span className="text-sm">
              {t("productsPage.filters.sortOptions.priceLowHigh")}
            </span>
          </label>
          <label className="flex items-center gap-2.5 cursor-pointer">
            <RadioGroupItem value="price-desc" />
            <span className="text-sm">
              {t("productsPage.filters.sortOptions.priceHighLow")}
            </span>
          </label>
        </RadioGroup>
      </div>
        </>
      )}
    </div>
  );
}
