import { FiltersPrimitives } from "@codelytv/criteria";
import { Criteria } from "./critera";
import { DEFAULT_ORDER, INITIAL_PAGE_INDEX, INITIAL_PAGE_SIZE } from "./defaults";

type defaultsType = {
  order: "asc" | "desc";
  pageSize: number;
  pageNumber: number;
};

const defaultOptions: defaultsType = {
  order: DEFAULT_ORDER,
  pageSize: INITIAL_PAGE_SIZE,
  pageNumber: INITIAL_PAGE_INDEX,
} as const;

export class CriteriaFromUrlConverter {
  /**
   * Converts a URL to a criteria object.
   * @param url - The URL to convert.
   * @returns The criteria object.
   */
  public toCriteria(
    url: URL,
    options?: {
      defaults: defaultsType;
    }
  ): Criteria {
    const { searchParams: urlParams } = url;
    const defaults = {
      order: options?.defaults?.order ?? defaultOptions.order,
      pageSize: options?.defaults?.pageSize ?? defaultOptions.pageSize,
      pageNumber: options?.defaults?.pageNumber ?? defaultOptions.pageNumber,
    };

    const quickSearch = urlParams.get("q");

    const filters = this.parseFilters(urlParams);

    const orderBy = urlParams.get("orderBy");

    const order = urlParams.has("order") ? String(urlParams.get("order")) : defaults.order;

    const pageSize = this.parseInteger(urlParams.get("pageSize"), defaults.pageSize);
    const pageNumber = this.parseInteger(urlParams.get("pageNumber"), defaults.pageNumber);

    return Criteria.fromPrimitives(filters, orderBy, order, pageSize, pageNumber, quickSearch);
  }

  public toFiltersPrimitives(url: URL): FiltersPrimitives[] {
    const { searchParams } = url;

    return this.parseFilters(searchParams);
  }

  private parseInteger(value: string | null, fallback: number): number {
    const parsed = Number.parseInt(value ?? "", 10);
    return Number.isNaN(parsed) ? fallback : parsed;
  }

  private parseFilters(searchParams: URLSearchParams): FiltersPrimitives[] {
    const tempFilters: Record<string, Partial<FiltersPrimitives>> = {};

    searchParams.forEach((value, key) => {
      const match = key.match(/filters\[(\d+)]\[(.+)]/);
      if (match) {
        const index = match[1];
        const property = match[2] as keyof FiltersPrimitives;
        // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
        if (!tempFilters[index]) {
          tempFilters[index] = {};
        }
        tempFilters[index][property] = value;
      }
    });

    // @ts-ignore
    return Object.values(tempFilters).filter(
      (filter) =>
        filter.field !== undefined && filter.operator !== undefined && filter.value !== undefined
    );
  }
}
