import { useCallback, useEffect, useMemo, useState } from "react";
import { useDispatch, useSelector } from "react-redux";

import { useConfig } from "@hooks/useConfig.ts";
import { useDebounce } from "@uidotdev/usehooks";
import { isSolana } from "@utils/isSolana.ts";
import { isValidENS } from "@utils/isValidENS.ts";
import { onSetCustomRecipient } from "../analytics/events.ts";
import { usePasteFromClipboard } from "../hooks/usePasteFromClipboard";
import { useTheme } from "../hooks/useTheme";
import { type Validity, useValidateAddress } from "../hooks/useValidateAddress";
import { toggleRecipientModal } from "../store/globalSlice";
import { setReceiverAddress, setReceiverENS } from "../store/quoteParamSlice";
import type { ReduxStateType } from "../store/types";
import { getBorderRadius } from "../utils/getBorderRadius";
import { Button } from "./common/Button.tsx";
import { MIcon } from "./common/MIcon.tsx";
import { ModalHeader } from "./common/ModalHeader.tsx";
import { SlideInPanel } from "./common/SlideInPanel.tsx";
import { SquaredCheckbox } from "./common/SquaredCheckbox.tsx";

// @fixme: color tokens
// @todo: need to make recipient address mandatory for smart wallets

interface AddressInputProps {
  value: string;
  onChange: (value: string) => void;
  disabled?: boolean;
  onPaste: () => void;
  onClear: () => void;
}

const AddressInput: React.FC<AddressInputProps> = ({
  value,
  onChange,
  disabled,
  onPaste,
  onClear,
}) => {
  const theme = useTheme();

  return (
    <div
      className="bn-h-[52px] bn-border bn-border-solid bn-border-subtle bn-pl-4 bn-pr-2.5 bn-relative bn-flex bn-items-center bn-justify-between bn-bg-layer-2"
      style={{ borderRadius: getBorderRadius(theme.borderRadius, 8) }}
    >
      <input
        className="bn-bg-transparent bn-text-sm bn-font-medium bn-text-primary placeholder:bn-text-secondary bn-h-full bn-w-full bn-border-0 bn-mr-3 bn-overflow-ellipsis"
        value={value}
        onChange={(e) => onChange(e.target.value)}
        placeholder="Enter Recipient Address"
        spellCheck={false}
        id="bn-receiver-address"
        disabled={disabled}
        aria-label="Recipient address input"
      />
      {!disabled &&
        (value ? (
          <button
            className="bn-h-6 bn-w-6 bn-border-0 bn-flex bn-items-center bn-justify-center bn-cursor-pointer bn-text-primary bn-bg-transparent"
            type="button"
            onClick={onClear}
            aria-label="Clear address"
          >
            <MIcon name="backspace" />
          </button>
        ) : (
          <PasteButton onClick={onPaste} />
        ))}
    </div>
  );
};

interface ValidationBoxProps {
  status: Validity;
  network?: "solana" | "ethereum";
}

const ValidationBox: React.FC<ValidationBoxProps> = ({ status, network }) => {
  const getMsg = useCallback(() => {
    if (status.isContract) return "Smart contract";
    if (!status.isValid)
      return `Invalid${network ? ` ${network}` : ""} wallet address`;
    return null;
  }, [status, network]);

  const message = getMsg();
  if (!message) return null;

  const style = `bn-pl-1 bn-text-sm bn-font-normal bn-mt-2 ${
    status.isContract ? "bn-text-accent-1" : "bn-text-accent-4"
  }`;

  return <p className={style}>{message}</p>;
};

interface PasteButtonProps {
  onClick: () => void;
}

const PasteButton: React.FC<PasteButtonProps> = ({ onClick }) => {
  const theme = useTheme();
  return (
    <button
      type="button"
      className="bn-px-2 bn-py-1 bn-text-accent-1 bn-text-sm bn-font-medium bn-bg-accent-1 bn-border-0 bn-cursor-pointer"
      style={{ borderRadius: getBorderRadius(theme.borderRadius, 8) }}
      onClick={onClick}
      aria-label="Paste address from clipboard"
    >
      Paste
    </button>
  );
};

export const RecipientAddressModal: React.FC = () => {
  const isOpen = useSelector(
    (state: ReduxStateType) => state.global.showRecipientModal
  );

  const dispatch = useDispatch();

  const closePanel = useCallback(() => {
    dispatch(toggleRecipientModal(false));
  }, [dispatch]);

  return (
    <SlideInPanel isVisible={isOpen} closePanel={closePanel}>
      <RecipientAddressModalContent closePanel={closePanel} />
    </SlideInPanel>
  );
};

const RecipientAddressModalContent = ({
  closePanel,
}: {
  closePanel: () => void;
}) => {
  const { eventHandlers } = useConfig();
  const dispatch = useDispatch();

  const toChainId = useSelector(
    (state: ReduxStateType) => state.quoteParams.toChainId
  );

  const recipientNetwork = isSolana(toChainId ?? 0) ? "solana" : "ethereum";

  const receiver = useSelector(
    (state: ReduxStateType) => state.quoteParams.receiver
  );

  useEffect(() => {
    if (!receiver) {
      setDisclaimer(false);
    }
    setValue(receiver || "");
  }, [receiver]);

  const [value, setValue] = useState("");
  const [disclaimer, setDisclaimer] = useState(false);

  const { state: copiedAddress, pasteFromClipboard } = usePasteFromClipboard();
  const debouncedAddress = useDebounce(value, 300);

  const { state: addressStatus, address } = useValidateAddress({
    value: debouncedAddress,
    toChainId: toChainId ?? undefined,
  });

  const dispatchRecipientAddress = useCallback(() => {
    onSetCustomRecipient({ enabled: !!address });
    if (!address) return;

    dispatch(setReceiverAddress(address));

    if (isValidENS(value)) {
      dispatch(setReceiverENS(value));
    } else {
      dispatch(setReceiverENS(null));
    }
    closePanel();
  }, [address, value, dispatch, closePanel]);

  const removeRecipientAddress = () => {
    setValue("");
    setDisclaimer(false);
  };

  useEffect(() => {
    if (copiedAddress) {
      setValue(copiedAddress);
    }
  }, [copiedAddress]);

  const isConfirmDisabled = useMemo(
    () => !address || !disclaimer || !addressStatus.isValid,
    [address, disclaimer, addressStatus.isValid]
  );
  return (
    <>
      <ModalHeader
        label={"Recipient Address"}
        closeModal={closePanel}
        subText="Swap and send tokens to another address"
        classNames="bn-border-0"
      />

      <div className="bn-px-4 bn-mt-2">
        <AddressInput
          value={value}
          onChange={setValue}
          onPaste={pasteFromClipboard}
          onClear={removeRecipientAddress}
        />

        {address && (
          <ValidationBox
            status={addressStatus}
            network={recipientNetwork ?? undefined}
          />
        )}
      </div>

      <div className="bn-p-4">
        <div className="bn-flex bn-items-center bn-mb-4">
          <SquaredCheckbox
            id="recipient-address-checkbox"
            active={disclaimer}
            setActive={setDisclaimer}
          />
          <p className="bn-ml-1.5 bn-text-secondary bn-font-normal bn-text-sm">
            The address is correct and not an exchange wallet.{" "}
            <span className="bn-text-accent-1">
              Tokens sent to the wrong address can't be retrieved.
            </span>
          </p>
        </div>

        <Button
          onClick={dispatchRecipientAddress}
          label="Confirm Recipient Address"
          disabled={isConfirmDisabled}
        />

        {recipientNetwork && eventHandlers?.onOpenWalletConnect && (
          <div className="bn-flex bn-items-center bn-justify-center">
            <button
              type="button"
              onClick={() =>
                eventHandlers?.onOpenWalletConnect?.(
                  recipientNetwork === "solana" ? "solana" : "eip155"
                )
              }
              className="bn-mt-6 bn-text-theme bn-font-medium bn-text-base bn-underline bn-cursor-pointer bn-text-center"
            >
              Or Connect{" "}
              <span className="bn-capitalize">{recipientNetwork}</span> Wallet
            </button>
          </div>
        )}
      </div>
    </>
  );
};
