import clsx from 'clsx';
import { useAppDispatch } from '@akinon/next/redux/hooks';
import { Facet, FacetChoice } from '@akinon/next/types';
import {
  Accordion,
  Radio,
  Checkbox,
  LoaderSpinner,
  Button,
  Icon
} 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;
}

interface FilterItemProps {
  facet: any;
  isPending: boolean;
  startTransition: (callback: () => void) => void;
  isDropdown?: boolean;
  itemPaddingY?: number;
  itemPaddingX?: number;
  itemMarginBottom?: number;
}

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,
  isDropdown = false,
  itemPaddingY = 6,
  itemPaddingX = 0,
  itemMarginBottom = 0
}: FilterItemProps) => {
  const dispatch = useAppDispatch();
  const router = useRouter();
  const pathname = usePathname();

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

  const handleSelectFilter = ({
    facet,
    choice
  }: {
    facet: Facet;
    choice: FacetChoice;
  }) => {
    setIsDrawerOpen(false);
    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 || [])]);

  const choiceItemStyles = {
    paddingTop: `${itemPaddingY}px`,
    paddingBottom: `${itemPaddingY}px`,
    paddingLeft: `${itemPaddingX}px`,
    paddingRight: `${itemPaddingX}px`,
    marginBottom: `${itemMarginBottom}px`
  };

  const renderChoice = (choice: FacetChoice, index: number) => (
    <div key={choice.label} className="relative" style={choiceItemStyles}>
      <Component
        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>
  );

  const renderChoices = (className: string) => (
    <div className={className}>
      {choices.map((choice, index) => renderChoice(choice, index))}
    </div>
  );

  const containerStyles = {
    paddingTop: `${itemPaddingY}px`,
    paddingBottom: `${itemPaddingY}px`,
    paddingLeft: `${itemPaddingX}px`,
    paddingRight: `${itemPaddingX}px`,
    marginBottom: `${itemMarginBottom}px`
  };

  return (
    <div style={containerStyles}>
      {isDropdown ? (
        renderChoices(
          clsx({
            'flex flex-wrap gap-4': facet.key === sizeKey,
            'space-y-2': facet.key !== sizeKey
          })
        )
      ) : (
        <>
          <div className="block lg:hidden">
            <Button
              className="w-full flex justify-between items-center text-base hover:bg-transparent hover:text-black-750 p-0"
              appearance="ghost"
              onClick={() => setIsDrawerOpen(true)}
            >
              <span>{facet.name}</span>
              <Icon name="arrow-right" size={20} />
            </Button>

            {isDrawerOpen && (
              <div className="absolute w-full top-16 inset-x-0 bottom-0 z-50 bg-white">
                <div className="flex items-center text-black-750 text-sm">
                  <Button
                    type="button"
                    className="text-sm hover:bg-transparent hover:text-black-750"
                    appearance="ghost"
                    onClick={() => setIsDrawerOpen(false)}
                  >
                    <Icon name="arrow-left" size={16} />
                  </Button>
                  <span className="text-sm">{facet.name}</span>
                </div>
                <div className="p-4 overflow-y-auto h-full">
                  {renderChoices(
                    clsx('flex gap-4', {
                      'flex-wrap flex-row': facet.key === sizeKey,
                      'flex-col': facet.key !== sizeKey
                    })
                  )}
                </div>
              </div>
            )}
          </div>

          <div className="hidden lg:block">
            <Accordion
              key={facet.key}
              title={facet.name}
              isCollapse={choices.some((choice) => choice.is_selected)}
              dataTestId={`filter-${facet.name}`}
            >
              {renderChoices(
                clsx('flex gap-4', {
                  'flex-wrap flex-row': facet.key === sizeKey,
                  'flex-col': facet.key !== sizeKey
                })
              )}
            </Accordion>
          </div>
        </>
      )}
    </div>
  );
};
