import type { DealType } from '@/lib/deal-types';
import { isDealType } from '@/lib/deal-types';
import type { SearchSort } from '@/lib/enums/search-sort';
import { SEARCH_SORT } from '@/lib/enums/search-sort';
import { clampInt, csvBuild, csvParse } from '@/lib/url/queryCodec';
import type { UrlCodec } from '@/lib/url/useUrlFilterState';

const SEARCH_SORTS = new Set<SearchSort>(SEARCH_SORT);

export interface SearchUrlState {
  q: string;
  categorySlug?: string;
  tagSlugs: string[];
  sort: string;
  page: number;
  minPrice: number;
  maxPrice: number;
  types: DealType[];
  discountTiers: string[];
}

export interface MakeSearchCodecOpts {
  locale: 'he' | 'en';
  priceCeiling: number;
}

function searchPath(_locale: MakeSearchCodecOpts['locale']): string {
  // No /en/search route in this worktree — both locales use /search.
  return '/search';
}

function parseSearchSort(raw: string | null): SearchSort {
  if (raw && SEARCH_SORTS.has(raw as SearchSort)) return raw as SearchSort;
  return 'relevance';
}

function parseDealTypes(raw: string | null): DealType[] {
  return csvParse(raw).filter(isDealType);
}

export function makeSearchCodec(opts: MakeSearchCodecOpts): UrlCodec<SearchUrlState> {
  const { locale, priceCeiling } = opts;
  const basePath = searchPath(locale);

  return {
    parse(loc) {
      const sp = new URLSearchParams(loc.search);
      const categorySlug = sp.get('category') ?? undefined;
      const tagSlugs = csvParse(sp.get('tagSlugs'));
      const sort = parseSearchSort(sp.get('sort'));
      const page = clampInt(sp.get('page'), { min: 1, max: Number.MAX_SAFE_INTEGER, fallback: 1 });
      const minPrice = clampInt(sp.get('minPrice'), {
        min: 0,
        max: Number.MAX_SAFE_INTEGER,
        fallback: 0,
      });
      const maxPrice = clampInt(sp.get('maxPrice'), {
        min: 0,
        max: Number.MAX_SAFE_INTEGER,
        fallback: priceCeiling,
      });

      return {
        q: sp.get('q') ?? '',
        categorySlug: categorySlug || undefined,
        tagSlugs,
        sort,
        page,
        minPrice,
        maxPrice: sp.get('maxPrice') == null ? priceCeiling : maxPrice,
        types: parseDealTypes(sp.get('type')),
        discountTiers: csvParse(sp.get('discount')),
      };
    },

    build(state) {
      const sp = new URLSearchParams();
      const q = state.q.trim();
      if (q) sp.set('q', q);
      if (state.categorySlug) sp.set('category', state.categorySlug);
      const tags = csvBuild(state.tagSlugs);
      if (tags) sp.set('tagSlugs', tags);
      const sort = parseSearchSort(state.sort);
      if (sort !== 'relevance') sp.set('sort', sort);
      if (state.page >= 2) sp.set('page', String(state.page));
      if (state.minPrice > 0) sp.set('minPrice', String(state.minPrice));
      if (state.maxPrice < priceCeiling) sp.set('maxPrice', String(state.maxPrice));
      const types = csvBuild(state.types);
      if (types) sp.set('type', types);
      const discount = csvBuild(state.discountTiers);
      if (discount) sp.set('discount', discount);

      const qs = sp.toString();
      return qs ? `${basePath}?${qs}` : basePath;
    },
  };
}
