import type { DealType } from '@/lib/deal-types';
import { isDealType } from '@/lib/deal-types';
import type { BrowseSort } from '@/lib/enums/search-sort';
import { BROWSE_SORT } from '@/lib/enums/search-sort';
import { buildDealsPath } from '@/lib/url/buildDealsPath';
import { clampInt } from '@/lib/url/queryCodec';
import { parseDealsPath } from '@/lib/url/parseDealsPath';
import type { UrlCodec } from '@/lib/url/useUrlFilterState';

const BROWSE_SORTS = new Set<BrowseSort>(BROWSE_SORT);
const NON_DEFAULT_SORTS = new Set<BrowseSort>(BROWSE_SORT.filter((s) => s !== 'hot'));

export interface DealsUrlState {
  type?: DealType;
  catSlug?: string;
  tagSlugs: string[];
  page: number;
  sort: BrowseSort;
  priceMin: number;
  priceMax: number;
}

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

function stripDealsPrefix(pathname: string): string {
  return pathname.replace(/^\/(?:(?:he|en)\/)?deals(?:\/|$)/, '').replace(/\/$/, '');
}

function parseBrowseSort(raw: string | null): BrowseSort {
  if (raw && NON_DEFAULT_SORTS.has(raw as BrowseSort)) return raw as BrowseSort;
  return 'hot';
}

export function makeDealsCodec(opts: MakeDealsCodecOpts): UrlCodec<DealsUrlState> {
  const { locale, priceCeiling } = opts;

  return {
    parse(loc) {
      const rawPath = stripDealsPrefix(loc.pathname);
      const parsed = parseDealsPath(rawPath);
      const sp = new URLSearchParams(loc.search);

      const type = parsed?.type && isDealType(parsed.type) ? parsed.type : undefined;
      const catSlug = parsed?.catSlug;
      const tagSlugs = parsed?.tagSlugs ?? [];
      const page = Math.max(1, parsed?.page ?? 1);
      const sort = parseBrowseSort(sp.get('sort'));
      const priceMin = clampInt(sp.get('priceMin'), {
        min: 0,
        max: Number.MAX_SAFE_INTEGER,
        fallback: 0,
      });
      const priceMax = clampInt(sp.get('priceMax'), {
        min: 0,
        max: Number.MAX_SAFE_INTEGER,
        fallback: 0,
      });

      return { type, catSlug, tagSlugs, page, sort, priceMin, priceMax };
    },

    build(state) {
      const path = buildDealsPath({
        locale,
        type: state.type,
        catSlug: state.catSlug,
        tagSlugs: state.tagSlugs,
        page: state.page,
      });

      const sp = new URLSearchParams();
      const sort = parseBrowseSort(BROWSE_SORTS.has(state.sort as BrowseSort) ? state.sort : null);
      if (NON_DEFAULT_SORTS.has(sort)) sp.set('sort', sort);
      if (state.priceMin > 0) sp.set('priceMin', String(state.priceMin));
      if (state.priceMax > 0 && state.priceMax < priceCeiling) {
        sp.set('priceMax', String(state.priceMax));
      }

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