import React, { useCallback, useEffect, useState } from "react";
import { Link, useHistory } from "react-router-dom";
import {
  InlineMessage,
  Input,
  PillInput,
  TalentButton,
  TalentButtonWithIcon,
  Typography,
} from "@komi-app/components";

import { getCampaignSDK, emailDomainService, services } from "services";

import CampaignTemplatePreview from "../../CampaignTemplatePreview";
import { CampaignTemplateBuilderEditModal } from "../../../Templates";
import { ErrorMessage } from "components/ProfileSettings/AudiencesAndCampaigns/EmailDomainSetup/EmailDomainSetupTile/ErrorMessage";
import { useEmailDomainQuery } from "components/ProfileSettings/AudiencesAndCampaigns/EmailDomainSetup/queries";

import {
  FieldValues,
  Path,
  useController,
  UseControllerProps,
  useForm,
} from "react-hook-form";

import { Segment } from "@komi-app/fans-sdk";
import classNames from "classnames";
import { FLAGS, useFeatureIsOn } from "@komi-app/flags-sdk";
import TemplateWithCursorGalleryModal from "../../Modals/TemplateGalleryModal";
import { useSessionFlag } from "hooks/useSessionFlag";
import { useModalState } from "hooks/useModalState";
import { SmartScheduleEducationModal } from "components/SmartScheduleEducationModal";
import { campaignCreateScheduleUrl } from "constants/dca";

import { EmailCampaignForm } from "@komi-app/messaging-sdk";

import "./EmailCampaignDetailsForm.scss";
import { CampaignFormCombobox } from "../../CampaignForm/CampaignFormCombobox";

import When from "@komi-app/when";
import {
  ButtonType,
  Message,
  MessageSemantic,
  Semantic,
} from "@komi-app/creator-ui";
import { useCampaignFormQuota } from "./queries";

export interface CampaignFormProps {
  initialValues: Partial<EmailCampaignForm>;
  isLoading: boolean;
  onSubmit: (values: Partial<EmailCampaignForm>) => Promise<void>;
  handleUnsavedChanges: (value: boolean) => void;
  campaignId?: string;
}

const CampaignForm = ({
  initialValues,
  isLoading,
  onSubmit,
  campaignId = "",
  handleUnsavedChanges,
}: CampaignFormProps) => {
  const isInvalidDraftPayloadFixOn = useFeatureIsOn(
    FLAGS.FIX_EMAIL_CAMPAIGN_DRAFT_PAYLOAD
  );

  const {
    isOpen: isEducationModalOpen,
    open: openEducationModal,
    close: closeEducationModal,
  } = useModalState();
  const [hasSeenEducationModal, markEducationModalAsSeen] = useSessionFlag(
    "shown_smart_schedule_education_modal",
    //NOTE: Update the default to false after fixing state issue
    true
  );
  const router = useHistory();
  const navigateToSmartSchedulePage = () => {
    const formValues = getValues();
    handleUnsavedChanges(false);

    const scheduleUrl = campaignId
      ? `${campaignCreateScheduleUrl}?id=${campaignId}`
      : campaignCreateScheduleUrl;

    router.push(scheduleUrl, { formValues });
  };

  const customDomainQuery = useEmailDomainQuery();

  const [segments, setSegments] = useState<Segment[]>([]);
  const [testEmails, setTestEmails] = useState<string[]>([]);
  const [isTemplateEdited, setIsTemplateEdited] = useState(false);

  const [nameAlreadyExists, setNameAlreadyExists] = useState(false);

  useEffect(() => {
    const getSegments = async () => {
      const fetchedSegments = await services.segment().getSegments({
        hasEmailRecipients: true,
      });
      setSegments(fetchedSegments);
    };

    getSegments();
  }, []);

  const { setValue, control, watch, trigger, getValues } = useForm<
    Partial<EmailCampaignForm>
  >({
    values: initialValues,
    mode: "all",
  });

  const campaignTemplateId = watch("campaignTemplateId");
  const subject = watch("subject");
  const name = watch("name");
  const selectedSegments = watch("segmentIds") || [];
  // const schedule = watch("schedule");

  const sendTestEmail = async () => {
    if (!campaignTemplateId) return;
    await emailDomainService.sendTestEmail({
      templateId: campaignTemplateId,
      emails: testEmails,
      subject: `Test email: ${subject}`,
    });
  };

  const confirmNameExistsAndSave = async () => {
    if (!name) {
      trigger("name");
      return;
    }
    const normalizedId = campaignId || undefined;
    const nameAlreadyExists = await getCampaignSDK().getCampaignNameExists({
      name,
      campaignId: normalizedId,
    });
    if (nameAlreadyExists) setNameAlreadyExists(true);
    else {
      onSubmit(getValues());
      handleUnsavedChanges(false);
    }
  };

  const validateName = async (): Promise<boolean> => {
    if (!name) {
      trigger("name");
      return false;
    }
    const normalizedId = campaignId || undefined;
    const nameAlreadyExists = await getCampaignSDK().getCampaignNameExists({
      name,
      campaignId: normalizedId,
    });
    if (nameAlreadyExists) {
      setNameAlreadyExists(true);
      return false;
    } else {
      return true;
    }
  };

  const validateForm = async (): Promise<boolean> => {
    const isNameValid = await validateName();
    const isSubjectValid = await trigger("subject");
    const isTemplateValid = await trigger("campaignTemplateId");
    const isSegmentValid = await trigger("segmentIds");

    return isNameValid && isSubjectValid && isTemplateValid && isSegmentValid;
  };

  const {
    isQuotaLimitingEnabled,
    hasQuotaLimitation,
    quotaLimitMessage,
    isQuotaPreventingSubmit,
  } = useCampaignFormQuota(selectedSegments);

  /**
   * Checks if the schedule button should be disabled
   * Check if the form is Loading
   * Also checks if the email domain is verified
   */
  const isSubmitEnabled = React.useMemo(() => {
    // keeping this separate for legibility
    if (isQuotaLimitingEnabled) {
      return (
        !isQuotaPreventingSubmit &&
        !isLoading &&
        customDomainQuery?.data?.status === "verified"
      );
    }
    return !isLoading && customDomainQuery?.data?.status === "verified";
  }, [
    isLoading,
    customDomainQuery?.data?.status,
    isQuotaLimitingEnabled,
    isQuotaPreventingSubmit,
  ]);

  const onScheduleClick = async () => {
    const isFormValid = await validateForm();
    if (!isFormValid || !isSubmitEnabled) {
      return;
    }

    if (hasSeenEducationModal) {
      //TODO : perform the campaign name exists check before redirecting to next page
      navigateToSmartSchedulePage();
    } else {
      openEducationModal();
    }
  };

  const onSaveAndExit = async () => {
    const isFormValid = await validateForm();
    if (!isFormValid) {
      return;
    }

    onSubmit(getValues());
    handleUnsavedChanges(false);
  };

  /**
   * Check if the user has configured domains.
   * If yes, check if the domain is verified.
   * If not, show the error message.
   */
  const getDomainConfigurationMessage = () => {
    if (customDomainQuery.data) {
      switch (customDomainQuery.data.status) {
        case "issue":
          return <ErrorMessage state={customDomainQuery.data} />;
        case "empty":
        case "pending":
          return (
            <InlineMessage
              type="error"
              message={
                <>
                  Connect your email domain in order to be able to send
                  campaigns to your audience.
                  <Link to="/admin/settings/audiences-and-campaigns">
                    &nbsp;Go to Settings
                  </Link>
                </>
              }
            />
          );
        default:
          return null;
      }
    } else {
      return null;
    }
  };

  const handleFormCheck = useCallback(() => {
    const currentFormValues = getValues();
    const hasUnsavedChanges: boolean =
      currentFormValues.name !== initialValues.name ||
      currentFormValues.subject !== initialValues.subject ||
      isTemplateEdited ||
      Boolean(currentFormValues?.segmentIds?.length);
    handleUnsavedChanges(hasUnsavedChanges);
  }, [campaignTemplateId, initialValues, isTemplateEdited]);

  useEffect(() => {
    if (isTemplateEdited) {
      handleFormCheck();
    }
  }, [isTemplateEdited]);

  return (
    <>
      {getDomainConfigurationMessage()}

      <form onChange={handleFormCheck}>
        <div className="details">
          <Typography.Heading level={4}>Details</Typography.Heading>
          <div className="details-content">
            <ControlledInput
              controllerProps={{
                control: control,
                name: "name",
                rules: { required: "Enter campaign name" },
              }}
              inputProps={{
                "data-testid": "campaign-title-input",
                label: "Campaign name",
                placeholder: "Enter campaign name",
              }}
              fieldError={
                nameAlreadyExists
                  ? "A campaign with the same name already exists"
                  : ""
              }
              onValueUpdate={() => {
                setNameAlreadyExists(false);
              }}
            />

            <ControlledInput
              controllerProps={{
                control: control,
                name: "subject",
                rules: { required: "Enter subject" },
              }}
              inputProps={{
                "data-testid": "campaign-subject-input",
                label: "Subject",
                placeholder: "Enter subject",
              }}
            />
            <CampaignFormCombobox
              controllerProps={{
                control: control,
                name: "segmentIds",
                rules: {
                  required: "Select segment",
                },
              }}
              label="Send to"
              onChangeHandler={handleFormCheck}
              options={segments.map((segment) => ({
                label: segment.name,
                value: segment.segmentId,
              }))}
            />
          </div>
        </div>

        <div className="email-content">
          <Typography.Heading className="email-content-heading" level={4}>
            Email Content
          </Typography.Heading>
          <ControlledCampaignTemplatePreview
            controllerProps={{
              control,
              name: "campaignTemplateId",
              rules: { required: "Select template" },
            }}
            onOpen={() => {
              setIsTemplateEdited(true);
            }}
          />

          {campaignTemplateId && (
            <div className="action-buttons">
              <CampaignTemplateBuilderEditModal
                templateId={campaignTemplateId}
                onOpen={() => {
                  setIsTemplateEdited(true);
                }}
              />
              <TemplateWithCursorGalleryModal
                disabled={false}
                onTemplateSelected={(template) => {
                  setValue("campaignTemplateId", template.templateId);
                }}
                onCancel={() => {}}
                buttonType="text"
                onOpen={() => {
                  setIsTemplateEdited(true);
                }}
              />
            </div>
          )}
        </div>

        {campaignTemplateId && (
          <div className="send-test-email">
            <Typography.Heading level={4}>Send Test Email</Typography.Heading>
            <Typography.Body color="gray-700">
              Sending a test email to your recipients to see a preview of what
              your email will look like
            </Typography.Body>
            <PillInput
              placeholder="Email address"
              validationErrorMessage="Enter a valid email"
              validationRegexType="email"
              emptyErrorMessage="Enter an email"
              title="Recipients"
              onValuesChanged={setTestEmails}
            />
            <div className="action-buttons">
              <TalentButtonWithIcon
                type="text"
                label="Send"
                prefixIcon="send"
                onClick={sendTestEmail}
                disabled={
                  !campaignTemplateId ||
                  !subject ||
                  !name ||
                  !testEmails.length ||
                  (customDomainQuery.data &&
                    customDomainQuery.data.status !== "verified")
                }
              />
            </div>
          </div>
        )}

        <div className="footer">
          <When
            value={hasQuotaLimitation && quotaLimitMessage}
            then={
              <Message
                semantic={MessageSemantic.ERROR}
                text={`You've reached your ${quotaLimitMessage}. Upgrade your plan to schedule campaigns.`}
                buttonProps={{
                  label: "Contact Us",
                  href: "mailto:support@komi.io",
                  type: ButtonType.LINK,
                  semantic: Semantic.SECONDARY,
                  size: "xsmall",
                }}
              />
            }
          />
          <div className="footer-buttons">
            <TalentButton
              variant="secondary"
              type="button"
              disabled={isLoading}
              onClick={
                isInvalidDraftPayloadFixOn
                  ? onSaveAndExit
                  : confirmNameExistsAndSave
              }
            >
              SAVE & EXIT
            </TalentButton>
            <TalentButton
              type="button"
              onClick={onScheduleClick}
              disabled={!isSubmitEnabled}
            >
              SCHEDULE
            </TalentButton>
          </div>
          <SmartScheduleEducationModal
            visible={isEducationModalOpen}
            onSchedule={() => {
              markEducationModalAsSeen(true);
              navigateToSmartSchedulePage();
            }}
            onDismiss={() => {
              closeEducationModal();
            }}
          />
        </div>
      </form>
    </>
  );
};

export default CampaignForm;

type DataAttributes = Partial<Record<`data-testid`, string>>;
function ControlledInput<
  TFieldValues extends FieldValues = FieldValues,
  TName extends Path<TFieldValues> = Path<TFieldValues>,
>({
  controllerProps,
  inputProps,
  fieldError,
  onValueUpdate,
}: {
  controllerProps: UseControllerProps<TFieldValues, TName>;
  inputProps: React.ComponentProps<typeof Input> & DataAttributes;
  fieldError?: string;
  onValueUpdate?: (data: string) => void;
}) {
  const {
    field: { onChange, ...field },
    fieldState: { error },
  } = useController(controllerProps);
  return (
    <Input
      error={error?.message || fieldError}
      onValueChange={(data: string) => {
        onChange(data);
        onValueUpdate && onValueUpdate(data);
      }}
      {...inputProps}
      {...field}
    />
  );
}
function ControlledCampaignTemplatePreview<
  TFieldValues extends FieldValues = FieldValues,
  TName extends Path<TFieldValues> = Path<TFieldValues>,
>({
  controllerProps,
  onOpen,
}: {
  controllerProps: UseControllerProps<TFieldValues, TName>;
  onOpen: () => void;
}) {
  const {
    field,
    fieldState: { error },
  } = useController(controllerProps);

  return (
    <div>
      <div
        className={classNames("email-preview", {
          "email-preview--error": error,
        })}
      >
        <CampaignTemplatePreview
          templateId={field.value}
          onCancel={() => field.onBlur()}
          onTemplateSelected={(templateId: string) => {
            field.onBlur();
            field.onChange(templateId);
          }}
          onOpen={onOpen}
        />
      </div>
      {error && (
        <Typography.Body level={2} color="feedback-error">
          {error.message}
        </Typography.Body>
      )}
    </div>
  );
}
