import clsx from 'clsx';
import { useAppDispatch } from '@akinon/next/redux/hooks';
import { Facet, FacetChoice } from '@akinon/next/types';
import { Accordion, Radio, Checkbox, LoaderSpinner } from '../../../components';
import { WIDGET_TYPE } from '../../../types';
import { SizeFilter } from './size-filter';
import { toggleFacet } from '@theme/redux/reducers/category';
import { commonProductAttributes } from '@theme/settings';
import { useRouter } from '@akinon/next/hooks';
import { usePathname } from 'next/navigation';
import { useState } from 'react';

const COMPONENT_TYPES = {
  [WIDGET_TYPE.category]: Radio,
  [WIDGET_TYPE.multiselect]: Checkbox
};

const sizeKey = commonProductAttributes.find(
  (item) => item.translationKey === 'size'
).key;

interface Props {
  facet: Facet;
  isPending: boolean;
  startTransition: (callback: () => void) => void;
}

const sortByPredefinedOrder = (
  aLabel: string,
  bLabel: string,
  order: string[]
) => {
  const aIndex = order.indexOf(aLabel);
  const bIndex = order.indexOf(bLabel);

  if (aIndex !== -1 && bIndex !== -1) return aIndex - bIndex;
  if (aIndex !== -1) return -1;
  if (bIndex !== -1) return 1;

  return null;
};

const sortByNumericValue = (aLabel: string, bLabel: string) => {
  const aNum = parseInt(aLabel, 10);
  const bNum = parseInt(bLabel, 10);

  if (!isNaN(aNum) && !isNaN(bNum)) return aNum - bNum;
  if (!isNaN(aNum)) return -1;
  if (!isNaN(bNum)) return 1;

  return null;
};

const sortChoices = (
  facetKey: string,
  choices: FacetChoice[]
): FacetChoice[] => {
  if (facetKey === sizeKey) {
    const order = ['xs', 's', 'm', 'l', 'xl'];

    return choices.sort((a, b) => {
      const aLabel = a.label.toLowerCase();
      const bLabel = b.label.toLowerCase();

      const orderComparison = sortByPredefinedOrder(aLabel, bLabel, order);
      if (orderComparison !== null) return orderComparison;

      const numericComparison = sortByNumericValue(aLabel, bLabel);
      if (numericComparison !== null) return numericComparison;

      return aLabel.localeCompare(bLabel);
    });
  }

  return choices;
};

const getComponentByWidgetType = (widgetType: string, facetKey: string) => {
  if (facetKey === sizeKey) {
    return SizeFilter;
  }
  return COMPONENT_TYPES[widgetType] || COMPONENT_TYPES[WIDGET_TYPE.category];
};

export const FilterItem = ({ facet, isPending, startTransition }: Props) => {
  const dispatch = useAppDispatch();
  const router = useRouter();
  const pathname = usePathname();

  const [pendingChoice, setPendingChoice] = useState<string | null>(null);

  const handleSelectFilter = ({
    facet,
    choice
  }: {
    facet: Facet;
    choice: FacetChoice;
  }) => {
    setPendingChoice(choice.label);
    startTransition(() => {
      if (facet.key === 'category_ids') {
        router.push(choice.url);
      } else {
        dispatch(toggleFacet({ facet, choice }));
      }
      setPendingChoice(null);

      const urlSearchParams = new URLSearchParams(window.location.search);
      urlSearchParams.delete(facet.search_key);
      router.replace(pathname + '?' + urlSearchParams.toString());
    });
  };

  const Component = getComponentByWidgetType(facet.widget_type, facet.key);
  const choices = sortChoices(facet?.key, [...(facet?.data?.choices || [])]);

  return (
    <Accordion
      key={facet.key}
      title={facet.name}
      isCollapse={choices.some((choice) => choice.is_selected)}
      dataTestId={`filter-${facet.name}`}
    >
      <div
        className={clsx('flex gap-4', {
          'flex-wrap flex-row': facet.key === sizeKey,
          'flex-col': facet.key !== sizeKey
        })}
      >
        {choices.map((choice, index) => (
          <div key={choice.label} className="relative">
            <Component
              key={choice.label}
              data={choice}
              name={facet.key}
              onChange={() => handleSelectFilter({ facet, choice })}
              onClick={() =>
                facet.key === sizeKey && handleSelectFilter({ facet, choice })
              }
              checked={choice.is_selected}
              data-testid={`${choice.label.trim()}`}
              disabled={isPending}
            >
              {choice.label} (
              <span
                data-testid={`filter-count-${facet.name.toLowerCase()}-${index}`}
              >
                {choice.quantity}
              </span>
              )
            </Component>

            {isPending && pendingChoice === choice.label && (
              <div className="absolute inset-0 flex items-center justify-center z-50">
                <LoaderSpinner />
              </div>
            )}
          </div>
        ))}
      </div>
    </Accordion>
  );
};
