import { useState, FC, useMemo, useEffect, useRef } from "react";
import Switch from "react-switch";

import { WaitlistService, Environment } from "rm-sdk/build";
import { isEmail } from "../../utils/commonUtils";
import { Button } from "../../components/Button";
import { Checkbox } from "../../components/Checkbox";
import { TextInput } from "../../components/TextInput";
import { RadioList, IOption } from "../../components/RadioList";

import "./styles.scss";

enum SubscriptionType {
  Email = "email",
  Telegram = "telegram",
  EmailAndTelegram = "emailAndTelegram",
}

const SUBSCRIPTION_OPTIONS: IOption[] = [
  { label: "Email", value: SubscriptionType.Email },
  { label: "Telegram", value: SubscriptionType.Telegram },
  { label: "Email & Telegram", value: SubscriptionType.EmailAndTelegram },
];

const telegramIcon = (
  <svg width={20} height={20} viewBox="0 0 48 48" fill="white">
    <path d="M5.83,23.616c12.568-5.529,28.832-12.27,31.077-13.203c5.889-2.442,7.696-1.974,6.795,3.434 c-0.647,3.887-2.514,16.756-4.002,24.766c-0.883,4.75-2.864,5.313-5.979,3.258c-1.498-0.989-9.059-5.989-10.7-7.163 c-1.498-1.07-3.564-2.357-0.973-4.892c0.922-0.903,6.966-6.674,11.675-11.166c0.617-0.59-0.158-1.559-0.87-1.086 c-6.347,4.209-15.147,10.051-16.267,10.812c-1.692,1.149-3.317,1.676-6.234,0.838c-2.204-0.633-4.357-1.388-5.195-1.676 C1.93,26.43,2.696,24.995,5.83,23.616z"></path>
  </svg>
);

const CHECK_SUBSCRIPTION_INTERVAL = 3000;

interface IProps {
  environment: Environment;
  waitlistName: string;
  title: string;
  successText: string;
  subscriptionType: SubscriptionType;
  address?: string;
  emailPlaceholder?: string;
  submitButtonText?: string;
  telegramButtonText?: string;
  addressRequired?: boolean | "true" | "false";
  addressRequiredText?: string;
  option1?: string;
  option2?: string;
  option3?: string;
  option4?: string;
  option5?: string;
  showTextbox?: boolean | "true" | "false";
  textboxValueRequired?: boolean | "true" | "false";
  textboxLabel?: string;
  textboxPlaceholder?: string;
  textboxType?: "string" | "positiveNumber";
}

export const WaitlistWidget: FC<IProps> = (props) => {
  const {
    environment,
    waitlistName,
    title,
    successText,
    option1,
    option2,
    option3,
    option4,
    option5,
    emailPlaceholder = "Enter email",
    submitButtonText = "Submit",
    telegramButtonText = "Activate bot",
    address,
    addressRequired = false,
    addressRequiredText = "Please, connect your wallet",
    subscriptionType,
    showTextbox = false,
    textboxValueRequired = false,
    textboxLabel = "",
    textboxPlaceholder = "",
    textboxType = "string",
  } = props;

  const uuid = useMemo(() => crypto.randomUUID(), []);

  const waitlistService = useMemo(() => {
    const environmentNumber = parseInt(environment as unknown as string);

    return new WaitlistService(
      Number.isNaN(environmentNumber) ? environment : environmentNumber
    );
  }, [environment]);

  const [isOpen, setIsOpen] = useState(false);
  const [isComplete, setIsComplete] = useState(false);
  const [isSubmitted, setIsSubmitted] = useState(false);
  const [showValidationErrors, setShowValidationErrors] = useState(false);
  const [isInProgress, setIsInProgress] = useState(false);
  const [userSubscriptionType, setUserSubscriptionType] =
    useState<IOption["value"]>(subscriptionType);
  const [checkTelegramSubscription, setCheckTelegramSubscription] =
    useState(false);
  const [email, setEmail] = useState("");
  const [textboxValue, setTextboxValue] = useState("");
  const [error, setError] = useState<string | undefined>();
  const isAddressRequired =
    addressRequired === true || addressRequired === "true";
  const isShowTextbox = showTextbox === true || showTextbox === "true";
  const isTextboxValueRequired =
    textboxValueRequired === true || textboxValueRequired === "true";

  const [optionsState, setOptionsState] = useState<boolean[]>([]);
  const options = useMemo(
    () => [option1, option2, option3, option4, option5].filter(Boolean),
    [option1, option2, option3, option4, option5]
  );

  const saveWaitlistRequest = (
    optionsState: boolean[],
    email?: string,
    textboxLabel?: string,
    textboxValue?: string
  ) =>
    waitlistService.saveWaitlistRequest({
      uuid,
      waitlistName,
      email,
      address,
      option1: (optionsState[0] && options[0]) || undefined,
      option2: (optionsState[1] && options[1]) || undefined,
      option3: (optionsState[2] && options[2]) || undefined,
      option4: (optionsState[3] && options[3]) || undefined,
      option5: (optionsState[4] && options[4]) || undefined,
      location: location.href,
      textboxLabel: textboxValue ? textboxLabel : undefined,
      textboxValue,
    });

  const prevRequest = useRef<Promise<any>>(Promise.resolve());
  const nextRequest = useRef<
    { fn: () => Promise<any>; isInProgress: boolean } | undefined
  >();

  const createOptionHandler = (optionIndex: number) => (checked: boolean) => {
    const newOptionsState = [...optionsState];
    newOptionsState[optionIndex] = checked;

    const shouldRunRequest = !nextRequest.current;

    nextRequest.current = {
      isInProgress: false,
      fn: () => {
        return saveWaitlistRequest(newOptionsState)
          .catch(() => {})
          .then(() => {
            const request = nextRequest.current;
            nextRequest.current = undefined;

            if (request && !request.isInProgress) {
              prevRequest.current = prevRequest.current.then(request.fn);
            }
          });
      },
    };

    if (shouldRunRequest) {
      nextRequest.current.isInProgress = true;
      prevRequest.current = prevRequest.current.then(nextRequest.current.fn);
    }

    setOptionsState(newOptionsState);
  };

  const checkboxesError = !optionsState.some(Boolean)
    ? "You must select at least one option"
    : undefined;

  const emailError = !isEmail(email) ? "Invalid email" : undefined;
  const textboxError =
    isShowTextbox && textboxLabel && isTextboxValueRequired && !textboxValue
      ? "Field is required"
      : undefined;

  const isEmailRequired = [
    SubscriptionType.Email,
    SubscriptionType.EmailAndTelegram,
  ].includes(userSubscriptionType as SubscriptionType);
  const isTelegramRequired = [
    SubscriptionType.Telegram,
    SubscriptionType.EmailAndTelegram,
  ].includes(userSubscriptionType as SubscriptionType);

  const handleSubmit = async () => {
    setShowValidationErrors(true);
    setError(undefined);

    if (
      checkboxesError ||
      textboxError ||
      (isEmailRequired && emailError) ||
      (isAddressRequired && !address)
    ) {
      return;
    }

    setIsInProgress(true);
    try {
      await prevRequest.current;
      await saveWaitlistRequest(
        optionsState,
        email,
        textboxLabel,
        textboxValue
      );

      if (!isTelegramRequired) {
        setIsComplete(true);
      }
      setIsSubmitted(true);
    } catch (error) {
      setError("Something went wrong. Try again.");
    }

    setIsInProgress(false);
  };

  const handleTelegramButtonClick = () => {
    setShowValidationErrors(true);

    if (checkboxesError || textboxError || (isAddressRequired && !address)) {
      return;
    }

    if (!isEmailRequired && textboxValue) {
      prevRequest.current.then(() => {
        saveWaitlistRequest(optionsState, email, textboxLabel, textboxValue);
      });
    }

    setCheckTelegramSubscription(true);
    const telegramBotName = waitlistService.getTelegramBotName();
    window.open(`https://t.me/${telegramBotName}?start=${uuid}`, "_blank");
  };

  useEffect(() => {
    setUserSubscriptionType(subscriptionType);
  }, [subscriptionType]);

  useEffect(() => {
    if (!isOpen || !checkTelegramSubscription || !isTelegramRequired) {
      return;
    }

    const interval = setInterval(async () => {
      const isSubscribed = await waitlistService.checkTelegramSubscription(uuid);

      if (isSubscribed) {
        setCheckTelegramSubscription(false);
        setIsComplete(true);
      }
    }, CHECK_SUBSCRIPTION_INTERVAL);

    return () => clearInterval(interval);
  }, [checkTelegramSubscription && isOpen, isTelegramRequired]);

  const canUpdateForm = isInProgress || isSubmitted || checkTelegramSubscription;

  return (
    <div className="w-waitlist-widget">
      <div className="w-waitlist-widget__title">
        <Switch
          checked={isOpen}
          onChange={setIsOpen}
          disabled={isComplete}
          className={isOpen ? "w-waitlist-widget__switch--active" : undefined}
        />{" "}
        {isComplete ? successText : title}
      </div>
      {!isComplete && isOpen && (
        <div className="w-waitlist-widget__content">
          <div className="w-waitlist-widget__checkbox-list">
            {options.map((optionLabel, index) => (
              <Checkbox
                key={index}
                checked={optionsState[index]}
                onChange={createOptionHandler(index)}
                label={optionLabel}
                disabled={canUpdateForm}
              />
            ))}
            {showValidationErrors && checkboxesError && (
              <div className="w-waitlist-widget__error">{checkboxesError}</div>
            )}
          </div>
          {isShowTextbox && textboxLabel && (
            <TextInput
              label={textboxLabel}
              value={textboxValue}
              onChange={setTextboxValue}
              placeholder={textboxPlaceholder}
              size="small"
              type={textboxType}
              error={showValidationErrors ? textboxError : undefined}
              disabled={canUpdateForm}
            />
          )}
          {subscriptionType === SubscriptionType.EmailAndTelegram && (
            <RadioList
              label="Subscribe using:"
              options={SUBSCRIPTION_OPTIONS}
              selectedValue={userSubscriptionType}
              onChange={setUserSubscriptionType}
              orientation="horizontal"
              disabled={canUpdateForm}
            />
          )}
          {isEmailRequired && (
            <TextInput
              value={email}
              onChange={setEmail}
              placeholder={emailPlaceholder}
              size="small"
              error={showValidationErrors ? emailError : undefined}
              disabled={canUpdateForm}
            />
          )}
          {showValidationErrors && isAddressRequired && !address && (
            <div className="w-waitlist-widget__error">
              {addressRequiredText}
            </div>
          )}
          {error && <div className="w-waitlist-widget__error">{error}</div>}
          <div className="w-waitlist-widget__controls">
            {isEmailRequired && (
              <Button
                className={
                  isTelegramRequired
                    ? "w-waitlist-widget__telegram-button"
                    : undefined
                }
                onClick={handleSubmit}
                size="small"
                disabled={isInProgress || isSubmitted}
                loading={isInProgress}
              >
                {isTelegramRequired ? "1. " : ""}
                {submitButtonText}
              </Button>
            )}
            {isTelegramRequired && (
              <Button
                className="w-waitlist-widget__telegram-button"
                onClick={handleTelegramButtonClick}
                size="small"
                disabled={isEmailRequired && !isSubmitted}
                loading={checkTelegramSubscription}
              >
                {isEmailRequired ? "2. " : ""}
                {telegramButtonText}
                <div className="w-waitlist-widget__telegram-icon">
                  {telegramIcon}
                </div>
              </Button>
            )}
          </div>
        </div>
      )}
    </div>
  );
};
