import React, { useState, useEffect, useCallback, useRef } from 'react';
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import { useDispatch } from 'react-redux';
import { useAppSelector } from '@akinon/next/redux/hooks';
import { Button, Input, Icon } from '@akinon/next/components';
import { LoaderSpinner } from '@akinon/next/components';
import {
  createCreditCardFormSchema,
  type CreditCardFormData
} from '../utils/validation-schemas';
import {
  formatCardNumber,
  formatExpiryDate,
  formatCVV,
  detectCardType,
  getCvcLength,
  getCardIcon
} from '../utils/card-utils';
import { setNewCardFormData } from '../redux/reducer';
import clsx from 'clsx';
import MasterpassSecurityInfo from './masterpass-security-info';
import { CreditCardFormProps } from '../types/custom-render.types';

const CreditCardForm: React.FC<CreditCardFormProps> = ({
  onSaveCard,
  isLoading = false,
  showSaveOption = true,
  initialValues = {},
  onBinChange,
  texts
}) => {
  const dispatch = useDispatch();
  const { newCardFormData } = useAppSelector((state) => state.masterpassRest);

  const [cardType, setCardType] = useState<string>('unknown');
  const [isBinChecking, setIsBinChecking] = useState(false);
  const lastCheckedBinRef = useRef<string>('');
  const binCheckTimeoutRef = useRef<NodeJS.Timeout | null>(null);

  const validationSchema = React.useMemo(
    () => createCreditCardFormSchema(texts),
    [texts]
  );

  const {
    register,
    handleSubmit,
    watch,
    setValue,
    formState: { errors, isValid }
  } = useForm<CreditCardFormData>({
    resolver: yupResolver(validationSchema) as any,
    defaultValues: {
      cardNumber: '',
      expiryDate: '',
      cvv: '',
      cardholderName: '',
      saveCard: false,
      cardAlias: '',
      ...initialValues,
      ...newCardFormData
    },
    mode: 'all'
  });

  const watchedCardNumber = watch('cardNumber');
  const watchedSaveCard = watch('saveCard');
  const watchedCardholderName = watch('cardholderName');
  const watchedExpiryDate = watch('expiryDate');
  const watchedCvv = watch('cvv');
  const watchedCardAlias = watch('cardAlias');

  useEffect(() => {
    const formData = {
      cardNumber: watchedCardNumber,
      cardholderName: watchedCardholderName,
      expiryDate: watchedExpiryDate,
      cvv: watchedCvv,
      saveCard: watchedSaveCard,
      cardAlias: watchedCardAlias
    };

    dispatch(setNewCardFormData(formData));
  }, [
    watchedCardNumber,
    watchedCardholderName,
    watchedExpiryDate,
    watchedCvv,
    watchedSaveCard,
    watchedCardAlias,
    dispatch
  ]);

  useEffect(() => {
    const detectedType = detectCardType(watchedCardNumber);
    setCardType(detectedType);

    if (binCheckTimeoutRef.current) {
      clearTimeout(binCheckTimeoutRef.current);
    }

    if (watchedCardNumber && onBinChange) {
      const cleanCardNumber = watchedCardNumber.replace(/\D/g, '');
      if (cleanCardNumber.length >= 6) {
        const bin = cleanCardNumber.substring(0, 6);

        if (bin !== lastCheckedBinRef.current) {
          binCheckTimeoutRef.current = setTimeout(() => {
            setIsBinChecking(true);
            lastCheckedBinRef.current = bin;

            onBinChange(bin).finally(() => {
              setIsBinChecking(false);
            });
          }, 500);
        }
      }
    }

    return () => {
      if (binCheckTimeoutRef.current) {
        clearTimeout(binCheckTimeoutRef.current);
      }
    };
  }, [
    watchedCardNumber,
    watchedCardholderName,
    watchedExpiryDate,
    watchedCvv,
    watchedSaveCard,
    watchedCardAlias,
    onBinChange
  ]);

  const onFormSubmit = (data: CreditCardFormData) => {
    if (data.saveCard && onSaveCard) {
      const cleanedData = {
        ...data,
        cardNumber: data.cardNumber.replace(/\D/g, '')
      };
      onSaveCard(cleanedData);
    }
  };

  const expectedCVVLength = getCvcLength(cardType);

  return (
    <div className="bg-[#ffffff] border border-[#eeeeee] shadow-sm">
      <div className="flex justify-start items-center border-b border-[#eeeeee] px-4 py-3 sm:px-6 sm:py-4">
        <div className="flex items-center gap-2">
          <Icon name="credit-card" size={20} className="text-[#9d9d9d]" />
          <span className="text-[#181818] text-lg font-medium sm:text-xl">
            {texts.creditCardInfoTitle}
          </span>
          {isBinChecking && (
            <div className="flex items-center gap-2 ml-auto">
              <LoaderSpinner className="w-4 h-4" />
              <span className="text-sm text-[#2d2d2d]">
                {texts.checkingCardText}
              </span>
            </div>
          )}
        </div>
      </div>

      <div className="p-4 sm:p-6">
        <form onSubmit={handleSubmit(onFormSubmit)} className="space-y-6">
          <div className="space-y-2">
            <label
              htmlFor="cardNumber"
              className="block text-sm font-medium text-[#686868]"
            >
              {texts.cardNumberLabel}
            </label>
            <div className="relative">
              <Input
                {...register('cardNumber')}
                id="cardNumber"
                type="text"
                placeholder={texts.cardNumberPlaceholder}
                onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
                  const formatted = formatCardNumber(e.target.value);
                  setValue('cardNumber', formatted, { shouldValidate: true });
                }}
                error={errors.cardNumber}
                maxLength={23}
                className="pr-20"
              />
              {cardType !== 'unknown' && (
                <div
                  className={clsx(
                    'absolute right-3 top-1/2 transform -translate-y-1/2',
                    errors.cardNumber && '-translate-y-full'
                  )}
                >
                  <span className="flex text-sm font-medium text-[#9d9d9d] bg-[#f5f5f5] px-2 py-1">
                    <img
                      src={
                        getCardIcon(watchedCardNumber.replace(/\D/g, '')).src
                      }
                      alt={cardType}
                      className="h-4"
                    />
                  </span>
                </div>
              )}
            </div>
          </div>

          <div className="space-y-2">
            <label
              htmlFor="cardholderName"
              className="block text-sm font-medium text-[#686868]"
            >
              {texts.cardholderNameLabel}
            </label>
            <Input
              {...register('cardholderName')}
              id="cardholderName"
              type="text"
              placeholder={texts.cardholderNamePlaceholder}
              error={errors.cardholderName}
            />
          </div>

          <div className="grid grid-cols-2 gap-4">
            <div className="space-y-2">
              <label
                htmlFor="expiryDate"
                className="block text-sm font-medium text-[#686868]"
              >
                {texts.expiryDateLabel}
              </label>
              <Input
                {...register('expiryDate')}
                id="expiryDate"
                type="text"
                placeholder={texts.expiryDatePlaceholder}
                onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
                  const formatted = formatExpiryDate(e.target.value);
                  setValue('expiryDate', formatted, { shouldValidate: true });
                }}
                error={errors.expiryDate}
                maxLength={5}
              />
            </div>
            <div className="space-y-2">
              <label
                htmlFor="cvv"
                className="block text-sm font-medium text-[#686868]"
              >
                {texts.cvcLabel}
              </label>
              <Input
                {...register('cvv')}
                id="cvv"
                type="text"
                placeholder={
                  expectedCVVLength === 4
                    ? texts.cvcPlaceholder4
                    : texts.cvcPlaceholder3
                }
                onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
                  const formatted = formatCVV(e.target.value);
                  setValue('cvv', formatted, { shouldValidate: true });
                }}
                error={errors.cvv}
                maxLength={expectedCVVLength}
              />
            </div>
          </div>

          {showSaveOption && (
            <div className="space-y-4 mt-4">
              <div className="flex items-start space-x-3">
                <input
                  {...register('saveCard')}
                  id="saveCard"
                  type="checkbox"
                  className="h-4 w-4 mt-0.5 text-[#000000] focus:ring-primary border-[#ebebeb]"
                />
                <label
                  htmlFor="saveCard"
                  className="text-sm font-medium text-[#686868] cursor-pointer"
                >
                  {texts.saveCardTermsPrefix}{' '}
                  <a
                    href="https://www.masterpassturkiye.com/terms-and-conditions"
                    target="_blank"
                    rel="noopener noreferrer"
                    className="text-[#000000] underline hover:text-[#181818]"
                  >
                    {texts.saveCardTermsLink}
                  </a>
                  {texts.saveCardTermsSuffix}
                </label>
              </div>
              {watchedSaveCard && (
                <>
                  <div className="space-y-2 pt-2">
                    <label
                      htmlFor="cardAlias"
                      className="block text-sm font-medium text-[#686868]"
                    >
                      {texts.cardAliasLabel}
                    </label>
                    <Input
                      {...register('cardAlias')}
                      id="cardAlias"
                      type="text"
                      placeholder={texts.cardAliasPlaceholder}
                      error={errors.cardAlias}
                    />
                  </div>
                  <MasterpassSecurityInfo texts={texts} />
                </>
              )}
            </div>
          )}

          {watchedSaveCard && (
            <div className="flex flex-col sm:flex-row gap-3 pt-6 border-t border-[#eeeeee]">
              <Button
                type="submit"
                className="flex-1 group inline-flex items-center justify-center disabled:opacity-50 disabled:cursor-not-allowed"
                disabled={isLoading || !isValid}
              >
                {texts.addCardButton}
              </Button>
            </div>
          )}
        </form>
      </div>
    </div>
  );
};

export default CreditCardForm;
