import { useEffect, useMemo, useState } from 'react';
import clsx from 'clsx';
import { useAppSelector } from '@akinon/next/redux/hooks';
import { useSetAddressesMutation } from '@akinon/next/data/client/checkout';
import { useAddAddressMutation } from '@akinon/next/data/client/address';
import { Button, Checkbox, Icon, Modal, Radio } from '@theme/components';
import { AddressForm } from '@theme/views/account/address-form';
import { useLocalization } from '@akinon/next/hooks';
import PluginModule, { Component } from '@akinon/next/components/plugin-module';
import type { RootState } from '@theme/redux/store';
import type { Address } from '@akinon/next/types';
import AccordionSection, { SectionStatus } from '../accordion-section';
import { AddressListSkeleton } from '../skeletons/address-skeleton';

interface AddressSectionProps {
  status: SectionStatus;
  onEdit: () => void;
  onComplete: () => void;
  editable?: boolean;
}

const AddressSection = ({
  status,
  onEdit,
  onComplete,
  editable = true
}: AddressSectionProps) => {
  const { t } = useLocalization();
  const [isModalOpen, setIsModalOpen] = useState(false);

  const addressList = useAppSelector(
    (state: RootState) => state.checkout.addressList
  );
  const preOrder = useAppSelector(
    (state: RootState) => state.checkout.preOrder
  );
  const {
    shipping_address,
    billing_address,
    billing_and_shipping_same,
    delivery_option
  } = preOrder ?? {};

  const [setAddresses, { isLoading: isSetting }] = useSetAddressesMutation();
  const [addAddress, { isLoading: isAdding }] = useAddAddressMutation();

  const [billingSameAsShipping, setBillingSameAsShipping] = useState(
    billing_and_shipping_same ?? true
  );

  useEffect(() => {
    setBillingSameAsShipping(billing_and_shipping_same ?? true);
  }, [billing_and_shipping_same]);

  const isRetailStore = delivery_option?.delivery_option_type === 'retail_store';
  const billingMatchesShipping =
    !!shipping_address?.pk &&
    !!billing_address?.pk &&
    shipping_address.pk === billing_address.pk;

  const handleSelectShipping = async (address: Address) => {
    const billingPk = billingSameAsShipping
      ? address.pk
      : billing_address?.pk ?? address.pk;
    await setAddresses({
      shippingAddressPk: address.pk,
      billingAddressPk: billingPk
    })
      .unwrap()
      .catch(() => null);
  };

  const handleSelectBilling = async (address: Address) => {
    if (!shipping_address?.pk) return;
    await setAddresses({
      shippingAddressPk: shipping_address.pk,
      billingAddressPk: address.pk
    })
      .unwrap()
      .catch(() => null);
  };

  const handleSameAddressToggle = async () => {
    const next = !billingSameAsShipping;
    setBillingSameAsShipping(next);
    if (next && shipping_address?.pk) {
      await setAddresses({
        shippingAddressPk: shipping_address.pk,
        billingAddressPk: shipping_address.pk
      })
        .unwrap()
        .catch(() => null);
    }
  };

  const handleAddAddress = async (data: Record<string, unknown>) => {
    const response = await addAddress({
      ...data,
      invalidateTag: 'Checkout'
    })
      .unwrap()
      .catch(() => null);
    setIsModalOpen(false);
    if (response?.pk) {
      const billingPk = billingSameAsShipping
        ? response.pk
        : billing_address?.pk ?? response.pk;
      await setAddresses({
        shippingAddressPk: response.pk,
        billingAddressPk: billingPk
      })
        .unwrap()
        .catch(() => null);
    }
  };

  const summary = useMemo(() => {
    if (!shipping_address) return null;
    return (
      <div className="flex flex-col gap-1">
        <span className="font-medium">{shipping_address.title}</span>
        <span className="text-xs text-black-700">
          {shipping_address.line} — {shipping_address.township?.name},{' '}
          {shipping_address.city?.name}
        </span>
        {!billingSameAsShipping &&
          billing_address &&
          !billingMatchesShipping && (
            <span className="text-xs italic text-gray-700">
              {t('checkout.one_page.address.billing_label')}: {billing_address.title}
            </span>
          )}
      </div>
    );
  }, [
    shipping_address,
    billing_address,
    billingSameAsShipping,
    billingMatchesShipping,
    t
  ]);

  const renderAddressCard = (
    address: Address,
    selected: boolean,
    onClick: () => void,
    name: string,
    options?: { showSameBadge?: boolean }
  ) => (
    <button
      key={`${name}-${address.pk}`}
      type="button"
      role="radio"
      aria-checked={selected}
      onClick={onClick}
      disabled={isSetting}
      className={clsx(
        'relative w-full rounded-sm border p-3 text-left shadow-sm transition-all',
        'hover:border-secondary-400 focus:outline-none focus-visible:ring-2 focus-visible:ring-secondary',
        selected
          ? 'border-secondary-400 ring-2 ring-secondary-400/30'
          : 'border-gray-300',
        isSetting && 'opacity-60'
      )}
      data-testid={`${name}-address-${address.pk}`}
    >
      <div className="flex items-start gap-3">
        <Radio name={name} checked={selected} onChange={() => null} />
        <div className="flex flex-1 flex-col gap-1 text-xs leading-snug">
          <div className="flex items-center gap-2">
            <span className="font-medium text-black-800">{address.title}</span>
            {options?.showSameBadge && (
              <span className="rounded-sm bg-gray-100 px-1.5 py-0.5 text-[10px] uppercase tracking-wide text-gray-700">
                {t('checkout.one_page.address.same_as_shipping')}
              </span>
            )}
          </div>
          <span className="text-black-700">{address.phone_number}</span>
          <span className="line-clamp-2 text-black-700">{address.line}</span>
          <span className="text-black-700">
            {address.township?.name} / {address.city?.name}
          </span>
        </div>
      </div>
    </button>
  );

  const isLoadingFirstLoad = !preOrder && addressList.length === 0;

  return (
    <AccordionSection
      step={2}
      title={t('checkout.one_page.address.title')}
      status={status}
      onEdit={onEdit}
      editable={editable}
      summary={summary}
      dataTestId="one-page-address"
    >
      {isLoadingFirstLoad ? (
        <AddressListSkeleton />
      ) : (
        <div className="flex flex-col gap-5">
          <div>
            <div className="mb-3 flex items-center justify-between gap-2">
              <h3 className="text-sm font-medium text-black-800">
                {t('checkout.one_page.address.shipping_label')}
              </h3>
              {!isRetailStore && (
                <Checkbox
                  checked={billingSameAsShipping}
                  onChange={handleSameAddressToggle}
                  data-testid="one-page-billing-same"
                >
                  <span className="text-xs">
                    {t('checkout.one_page.address.use_for_billing')}
                  </span>
                </Checkbox>
              )}
            </div>
            <div
              className="grid grid-cols-1 gap-2 md:grid-cols-2"
              role="radiogroup"
              aria-label={t('checkout.one_page.address.shipping_label')}
            >
              {addressList.map((address) =>
                renderAddressCard(
                  address,
                  shipping_address?.pk === address.pk,
                  () => handleSelectShipping(address),
                  'one-page-shipping'
                )
              )}
              <PluginModule
                component={Component.ClickCollect}
                props={{ addressTypeParam: 'shippingAddressPk' }}
              />
              <button
                type="button"
                onClick={() => setIsModalOpen(true)}
                disabled={isAdding}
                className={clsx(
                  'flex min-h-[5.5rem] items-center justify-center gap-2',
                  'rounded-sm border border-dashed border-gray-400 px-3 text-xs',
                  'text-black-700 transition-colors hover:border-secondary hover:text-secondary',
                  'focus:outline-none focus-visible:ring-2 focus-visible:ring-secondary',
                  'disabled:cursor-not-allowed disabled:opacity-50'
                )}
                data-testid="one-page-address-add"
              >
                <Icon name="plus" size={12} />
                {t('checkout.address.add_new_address')}
              </button>
            </div>
          </div>

          {!billingSameAsShipping && !isRetailStore && (
            <div>
              <div className="mb-3 flex items-center justify-between gap-2">
                <h3 className="text-sm font-medium text-black-800">
                  {t('checkout.one_page.address.billing_label')}
                </h3>
                {billingMatchesShipping && (
                  <span className="text-xs italic text-gray-700">
                    {t('checkout.one_page.address.pick_different_billing')}
                  </span>
                )}
              </div>
              <div
                className="grid grid-cols-1 gap-2 md:grid-cols-2"
                role="radiogroup"
                aria-label={t('checkout.one_page.address.billing_label')}
              >
                {addressList.map((address) =>
                  renderAddressCard(
                    address,
                    billing_address?.pk === address.pk,
                    () => handleSelectBilling(address),
                    'one-page-billing',
                    {
                      showSameBadge:
                        billingMatchesShipping &&
                        billing_address?.pk === address.pk
                    }
                  )
                )}
              </div>
            </div>
          )}

          <div className="flex justify-end">
            <Button
              disabled={
                !shipping_address?.pk || !billing_address?.pk || isSetting
              }
              onClick={onComplete}
              data-testid="one-page-address-continue"
            >
              {t('checkout.one_page.continue_to_shipping')}
            </Button>
          </div>

          <Modal
            portalId="one-page-add-address-modal"
            title={t('checkout.address.add_new_address')}
            open={isModalOpen}
            setOpen={setIsModalOpen}
            className="w-full max-h-[90vh] overflow-y-auto sm:w-[28rem]"
          >
            <AddressForm onSubmit={handleAddAddress} />
          </Modal>
        </div>
      )}
    </AccordionSection>
  );
};

export default AddressSection;
