import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
import {
  setCurrentStep,
  setSelectedShippingOptions
} from '@akinon/next/redux/reducers/checkout';
import { RootState } from '@theme/redux/store';
import {
  useSetShippingOptionMutation,
  useSetAttributeBasedShippingOptionsMutation,
  useSetDataSourceShippingOptionsMutation
} from '@akinon/next/data/client/checkout';
import { Price, Button, Radio } from '@theme/components';
import { CheckoutStep } from '@akinon/next/types';
import { useLocalization } from '@akinon/next/hooks';

const ShippingOptions: React.FC = () => {
  const { t } = useLocalization();
  const dispatch = useAppDispatch();
  const {
    steps,
    shippingOptions,
    attributeBasedShippingOptions,
    dataSourceShippingOptions,
    preOrder,
    addressList,
    selectedShippingOptions
  } = useAppSelector((state: RootState) => state.checkout);
  const {
    shipping_option,
    shipping_address,
    attribute_based_shipping_options,
    data_source_shipping_options
  } = preOrder ?? {};

  const [setShippingOption] = useSetShippingOptionMutation();
  const [setAttributeBasedShippingOptions] =
    useSetAttributeBasedShippingOptionsMutation();
  const [setDataSourceShippingOption] =
    useSetDataSourceShippingOptionsMutation();

  const prevAttributeBasedOptionsRef = useRef(attributeBasedShippingOptions);

  const [selectedPks, setSelectedPks] = useState<
    { dataSourcePk: number; optionPk: number }[] | null
  >(null);

  const initializeSelectedOptions = useCallback(() => {
    if (attribute_based_shipping_options) {
      const newSelected = { ...selectedShippingOptions };
      let hasChanges = false;

      Object.entries(attributeBasedShippingOptions).forEach(
        ([color, options]) => {
          if (
            !newSelected[color] ||
            !options.some((opt) => opt.pk === newSelected[color])
          ) {
            newSelected[color] = options[0].pk;
            hasChanges = true;
          }
        }
      );

      if (hasChanges) {
        dispatch(setSelectedShippingOptions(newSelected));
        setAttributeBasedShippingOptions(newSelected);
      }
    } else if (shippingOptions.length > 0 && !shipping_option) {
      setShippingOption(shippingOptions[0].pk);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [
    attributeBasedShippingOptions,
    selectedShippingOptions,
    setAttributeBasedShippingOptions,
    attribute_based_shipping_options,
    shippingOptions,
    shipping_option,
    setShippingOption
  ]);

  useEffect(() => {
    if (!data_source_shipping_options) return;

    const initialSelectedPks = data_source_shipping_options.map((option) => ({
      dataSourcePk: option.data_source.pk,
      optionPk: option.pk
    }));

    setSelectedPks(initialSelectedPks);
  }, [data_source_shipping_options]);

  useEffect(() => {
    if (
      JSON.stringify(prevAttributeBasedOptionsRef.current) !==
        JSON.stringify(attributeBasedShippingOptions) ||
      Object.keys(selectedShippingOptions).length === 0 ||
      (!shipping_option && shippingOptions.length > 0)
    ) {
      initializeSelectedOptions();
      prevAttributeBasedOptionsRef.current = attributeBasedShippingOptions;
    }
  }, [
    attributeBasedShippingOptions,
    selectedShippingOptions,
    initializeSelectedOptions,
    shipping_option,
    shippingOptions
  ]);

  const handleAttributeBasedOptionChange = useCallback(
    (color: string, newPk: number) => {
      const updatedOptions = { ...selectedShippingOptions, [color]: newPk };
      dispatch(setSelectedShippingOptions(updatedOptions));
      setAttributeBasedShippingOptions(updatedOptions);
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [selectedShippingOptions, setAttributeBasedShippingOptions]
  );

  if (addressList.length < 1) {
    return (
      <div className="w-full lg:w-2/5">
        <div className="border-b border-gray-400 px-8 py-4">
          <h2 className="text-2xl">{t('checkout.address.shipping.title')}</h2>
        </div>
        <div className="py-4 px-8">
          <p className="text-xs">
            {t('checkout.address.shipping.select_address_to_continue')}
          </p>
        </div>
      </div>
    );
  }

  const updateData = (dataSourcePk: number, newPk: number) => {
    const updatedSelectedPks = selectedPks?.map((item) =>
      item.dataSourcePk === dataSourcePk ? { ...item, optionPk: newPk } : item
    );

    if (!updatedSelectedPks) return;

    setSelectedPks(updatedSelectedPks);

    const pks = updatedSelectedPks.map((item) => item.optionPk);
    setDataSourceShippingOption(pks);
  };

  const handleRadioChange = (
    e: React.ChangeEvent<HTMLInputElement>,
    dataSourcePk: number
  ) => {
    const newPk = parseInt(e.currentTarget.value);
    updateData(dataSourcePk, newPk);
  };

  return (
    <div className="w-full lg:w-2/5">
      <div className="border-b border-gray-400 px-8 py-4">
        <h2 className="text-2xl">{t('checkout.address.shipping.title')}</h2>
      </div>
      {addressList.length < 1 ? (
        <div className="py-4 px-8">
          <p className="text-xs">
            {t('checkout.address.shipping.select_address_to_continue')}
          </p>
        </div>
      ) : (
        <div className="py-4 px-6">
          <p className="text-xs border-gray-400 pb-4">
            {t('checkout.address.shipping.chosen_address')}:{' '}
            {shipping_address?.city.name}
          </p>
          {shippingOptions && shippingOptions.length > 0 && (
            <>
              {shippingOptions.map((option) => (
                <div
                  key={option.pk}
                  className="py-4 border-t border-gray-400 flex justify-between"
                >
                  <Radio
                    name="shipping"
                    checked={option.pk === shipping_option?.pk}
                    onChange={() => {
                      setShippingOption(option.pk);
                    }}
                    onClick={() => {
                      setShippingOption(option?.pk);
                    }}
                    data-testid={`checkout-shipping-option-${option.pk}`}
                  >
                    {option.name}
                  </Radio>
                  <span className="text-xs">
                    <Price value={option.shipping_amount} />
                  </span>
                </div>
              ))}
            </>
          )}

          {attributeBasedShippingOptions &&
            Object.keys(attributeBasedShippingOptions).length > 0 &&
            Object.entries(attributeBasedShippingOptions).map(
              ([color, options]) => (
                <div key={color}>
                  <h3 className="text-lg font-bold">{color}</h3>
                  {options.map((option) => (
                    <div
                      key={option.pk}
                      className="py-4 border-t border-gray-400 flex justify-between"
                    >
                      <Radio
                        name={`attribute-based-shipping-${color}`}
                        checked={selectedShippingOptions[color] === option.pk}
                        onChange={() =>
                          handleAttributeBasedOptionChange(color, option.pk)
                        }
                        data-testid={`checkout-attribute-based-shipping-${option.pk}`}
                      >
                        {`${option.shipping_option_name}`}
                      </Radio>
                      <span className="text-xs">
                        <Price value={option.shipping_amount} />
                      </span>
                    </div>
                  ))}
                </div>
              )
            )}

          {dataSourceShippingOptions &&
            dataSourceShippingOptions.length > 0 &&
            dataSourceShippingOptions.map((option) => (
              <div key={option.pk}>
                <h3 className="text-lg font-bold">{option?.name}</h3>
                {option.data_source_shipping_options.map((opt) => (
                  <div
                    key={opt.pk}
                    className="py-4 border-t border-gray-400 flex justify-between"
                  >
                    <Radio
                      name={`data-source-shipping-${option.pk}`}
                      checked={
                        selectedPks?.some((item) => item.optionPk === opt.pk) ||
                        false
                      }
                      onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
                        handleRadioChange(e, option.pk)
                      }
                      value={opt.pk}
                      data-testid={`checkout-data-source-shipping-${opt.pk}`}
                    >
                      {opt?.shipping_option_name}
                    </Radio>
                    <span className="text-xs">
                      <Price value={opt?.shipping_amount} />
                    </span>
                  </div>
                ))}
              </div>
            ))}

          <Button
            className="mt-2 w-full"
            disabled={!steps.shipping.completed}
            onClick={() => dispatch(setCurrentStep(CheckoutStep.Payment))}
            data-testid="checkout-shipping-save"
          >
            {t('checkout.address.shipping.button')}
          </Button>
        </div>
      )}
    </div>
  );
};

export default ShippingOptions;
