import React, { MouseEvent, useEffect, useMemo, useState } from "react";
import { useHistory, useLocation } from "react-router-dom";

import { useSegmentsTotalRecipients } from "hooks/useEmailCampaignTotalRecipients";
import { useSessionFlag } from "hooks/useSessionFlag";

import {
  FLAGS,
  useFeatureIsOn,
} from "@komi-app/flags-sdk";

import {
  ButtonType,
  DropdownOption,
  SmartScheduleCreatePage,
  SmartScheduleFormViewProps,
  SmartSchedulePreviewProps,
  Time,
  Semantic,
  useToast,
  useModal,
  Stack,
  Button,
  SmartScheduleFormTabs,
} from "@komi-app/creator-ui";

import { getCampaignSDK } from "services";
import {
  CampaignScheduleType,
  CampaignType,
  EMAIL_CAMPAIGN_DEFAULT_FORM_VALUES,
  EMAIL_INITIAL_SUBSET_SIZE,
  EMAIL_INITIAL_GROWTH_RATE,
  EmailCampaignForm,
  ZEmailCampaignForm,
} from "@komi-app/messaging-sdk";

import {
  atOnceWarningMessage,
  campaignCreateUrl,
  campaignsUrl,
  infoMessage,
  largeSendWarningMessage,
  smartScheduleFindMoreURL,
} from "constants/dca";
import { emailCampaignCopy } from "constants/email/campaign";

import { calculateSchedulePreviewTableData } from "../../Utils";
import { createCampaignEditUrl } from "utils/dca/campaigns";
import { prune } from "utils/prune";

import { FormErrors } from "types/campaigns";
import { formErrors, formToPayload } from "../helpers";

export const EmailCampaignSchedulePage = () => {
  const location = useLocation<{ formValues: Partial<EmailCampaignForm> }>();

  const params = new URLSearchParams(location.search);
  const id = params.get("id");

  const prevPageUrl = id
    ? createCampaignEditUrl(id, CampaignType.SMART_SCHEDULE_EMAIL)
    : campaignCreateUrl;

  const router = useHistory();
  const { createToast } = useToast();

  const locationState = prune(location.state?.formValues);
  const formState = {
    ...EMAIL_CAMPAIGN_DEFAULT_FORM_VALUES,
    ...locationState,
  };
  const [formValues, setFormValues] = useState(formState);

  const [errors, setErrors] = useState<FormErrors<EmailCampaignForm>>({});
  const [displayDateTimeError, setDisplayDateTimeError] = useState(false);

  const useTiers = useFeatureIsOn(FLAGS.USE_TIERS_TALENT);
  const isStarterCreator = useFeatureIsOn(FLAGS.TIER_CREATOR_STARTER);
  const isTopCreator = useFeatureIsOn(FLAGS.TIER_CREATOR_TOP);

  const {
    Modal: ConfirmationModal,
    openModal: showConfirmation,
    closeModal: closeConfirmation,
  } = useModal();

  // TODO: single modal per page

  const {
    Modal: EducationModal,
    openModal: showEducation,
    closeModal: closeEducation,
  } = useModal();

  const [hasSeenEducationModal, markEducationModalAsSeen] = useSessionFlag(
    "shown_smart_schedule_education_modal",
    //NOTE: Update the default to false after fixing state issue
    true,
  );

  useEffect(() => {
    if (!hasSeenEducationModal) {
      showEducation();
    }
  }, []);

  const onCloseEducation = () => {
    closeEducation();
    markEducationModalAsSeen(true);
  };

  const totalRecipients = useSegmentsTotalRecipients(formState.segmentIds);

  const saveDraft = async () => {
    try {
      const payload = formToPayload(formValues);

      id
        ? await getCampaignSDK().email.updateOne(id, payload)
        : await getCampaignSDK().email.createOne(payload);

      router.push({
        pathname: campaignsUrl,
        state: { formValues },
      });
    } catch (error: any) {
      createToast({
        text: emailCampaignCopy.errors.cannotSave,
        semantic: "error",
        durationMs: 5000,
      });
    }
  };

  const handleSubmit = async () => {
    const errors = formErrors(formValues);
    closeConfirmation();

    if (Object.keys(errors).length) return setErrors({});

    if(useTiers) {
      if(!(isStarterCreator || isTopCreator)) {
        createToast({
          text: emailCampaignCopy.errors.noSubscription,
          semantic: "error",
          durationMs: 5000,
        });
        return;
      }
    }

    try {
      const payload = formToPayload(formValues);

      const campaign = id
        ? await getCampaignSDK().email.updateOne(id, payload)
        : await getCampaignSDK().email.createOne(payload);

      await getCampaignSDK().email.schedule(campaign.id);

      router.push({
        pathname: campaignsUrl,
        state: {
          toasts: [
            {
              text: `You’ve scheduled a new campaign “${payload.name}”.`,
              semantic: "success",
              durationMs: 5000,
            },
          ],
        },
      });
    } catch (error: any) {
      createToast({
        text: emailCampaignCopy.errors.cannotSchedule,
        semantic: "error",
        durationMs: 5000,
      });
    }
  };

  const handleTimeChange = (time: Partial<Time>) => {
    setFormValues((prev) => {
      setDisplayDateTimeError(false);

      return {
        ...prev,
        ...(time.hour !== undefined && { scheduledHour: Number(time.hour) }),
        ...(time.minute !== undefined && {
          scheduledMinute: Number(time.minute),
        }),
        ...(time.period !== undefined && { scheduledPeriod: time.period }),
      };
    });

    setErrors((prev) => ({
      ...prev,
      ...(time.hour !== undefined && { scheduledHour: undefined }),
      ...(time.minute !== undefined && { scheduledMinute: undefined }),
      ...(time.period !== undefined && { scheduledPeriod: undefined }),
    }));
  };

  function getMessage(
    scheduleType: CampaignScheduleType,
    initialDailySend?: number,
  ) {
    if (scheduleType === CampaignScheduleType.ALL_AT_ONCE) {
      return atOnceWarningMessage;
    }

    if (initialDailySend && initialDailySend > EMAIL_INITIAL_SUBSET_SIZE) {
      return largeSendWarningMessage;
    }

    return infoMessage;
  }

  const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();

    const parsedForm = ZEmailCampaignForm.required().safeParse(formValues);

    const { acceptedTerms } = formValues;
    const { scheduledTimestamp, scheduleType } = formToPayload(formValues);

    // Ensure the schedule is set to a date and time in the future
    if (scheduledTimestamp && scheduledTimestamp < new Date()) {
      setDisplayDateTimeError(true);
      return;
    }

    // Ensure the user has accepted the terms for all-in-one sends
    if (scheduleType === CampaignScheduleType.ALL_AT_ONCE && !acceptedTerms) {
      setErrors({
        acceptedTerms: emailCampaignCopy.errors.acceptedTerms,
      });
      return;
    }

    if (parsedForm.success) {
      setErrors({});
      showConfirmation();
    } else {
      const errors = formErrors(formValues);
      setErrors(errors);
    }
  };

  const onCancel = () => {
    router.push(prevPageUrl, { formValues });
  };

  const onClickPrevious = (e: MouseEvent) => {
    e.preventDefault();
    saveDraft();
  };

  const message = getMessage(formValues.scheduleType, formValues.initialSize);

  const formProps: SmartScheduleFormViewProps = {
    formId: "smart-schedule-form",
    disabled: false,
    timestamp: Date.now(), // TODO: replace this will `scheduledTimestamp`. See SB-1200
    labels: emailCampaignCopy.labels,
    placeholders: emailCampaignCopy.placeholders,
    helpers: {
      maxSend: "We'll use this number as a baseline for your sends on Day 1",
    },
    errors: {
      date: errors.scheduledDate,
      time: errors.scheduledMinute || errors.scheduledHour,
      timezone: errors.scheduledTimezone,
      maxSend: errors.initialSize,
      checkbox: errors.acceptedTerms,
    },
    tabOptions: [
      // TODO: refactor as tabs
      {
        label: "Smart schedule",
        onClickItem: () =>
          setFormValues((prev) => ({
            ...prev,
            scheduleType: CampaignScheduleType.SMART_SCHEDULE,
          })),
      },
      {
        label: "Send to everyone at once",
        onClickItem: () =>
          setFormValues((prev) => ({
            ...prev,
            scheduleType: CampaignScheduleType.ALL_AT_ONCE,
          })),
      },
    ],
    dateTimeErrorText: emailCampaignCopy.errors.futureDate,
    displayDateTimeError,
    messageText: message.text,
    messageSemantic: message.semantic,
    buttonProps: {
      label: "Find Out more",
      type: ButtonType.LINK,
      size: "small",
      onClick: () => {
        window.open(smartScheduleFindMoreURL, "_blank");
      },
    },
    initialTimezone: formValues.scheduledTimezone,
    onSubmit,
    onDateChange: (date) => {
      setFormValues((prev) => ({
        ...prev,
        scheduledDate: date,
      }));
      setErrors((prev) => ({
        ...prev,
        scheduledDate: undefined,
      }));
    },
    onTimeChange: handleTimeChange,
    onTimezoneSelect: (items) =>
      setFormValues((prev) => ({
        ...prev,
        scheduledTimezone: (items[0] as DropdownOption | undefined)?.value,
      })),
    onTextChange: (e) => {
      setFormValues((prev) => ({
        ...prev,
        initialSize: Number(e.target.value),
      }));
      setErrors((prev) => ({ ...prev, initialSize: undefined }));
    },
    onCheckboxChange: () => {
      setFormValues((prev) => ({
        ...prev,
        acceptedTerms: !prev.acceptedTerms,
      }));

      setErrors((prev) => ({ ...prev, acceptedTerms: undefined }));
    },
    checked: formValues.acceptedTerms,
    onChangeSelectedTab: (index) => {
      const allAtOnce = index === SmartScheduleFormTabs.ALL_AT_ONCE;

      setFormValues((prev) => ({
        ...prev,
        scheduleType: allAtOnce
          ? CampaignScheduleType.ALL_AT_ONCE
          : CampaignScheduleType.SMART_SCHEDULE,
        // FIXME: needs to be managed by the form
        ...(allAtOnce && { maxSendValue: formValues.initialSize || 0 }),
      }));
    },
    selectedTab:
      formValues.scheduleType === CampaignScheduleType.SMART_SCHEDULE ? 0 : 1,
    timeValue: {
      hour:
        formValues.scheduledHour && formValues.scheduledHour > 12
          ? formValues.scheduledHour - 12
          : formValues.scheduledHour,
      minute: formValues.scheduledMinute,
      period: formValues.scheduledPeriod as "AM" | "PM",
    },
    dateValue: formValues.scheduledDate,
    maxSendValue: formValues.initialSize?.toString(),
  };

  const tableData = calculateSchedulePreviewTableData({
    startDate: formValues.scheduledDate || undefined,
    totalRecipients: totalRecipients.data,
    growthRate: EMAIL_INITIAL_GROWTH_RATE,
    initialDailySends: Math.max(
      formValues.initialSize || 0,
      EMAIL_INITIAL_SUBSET_SIZE,
    ),
    scheduleType:
      formValues.scheduleType || CampaignScheduleType.SMART_SCHEDULE,
  });
  const completionDate = tableData[tableData.length - 1]?.date;
  const previewProps: SmartSchedulePreviewProps = {
    loading: totalRecipients.isLoading || totalRecipients.isError,
    recipientCountLoading: totalRecipients.isLoading || totalRecipients.isError,
    tableData: tableData,
    recipientCount: totalRecipients.data,
    completionDate: completionDate,
  };

  return (
    <>
      <SmartScheduleCreatePage
        formProps={formProps}
        pageTitle="Schedule Campaign"
        previewProps={previewProps}
        previousPageUrl={prevPageUrl}
        onClickPrevious={onClickPrevious}
        statusDetails={{
          text: "Draft",
          status: "warning",
        }}
        onCancel={onCancel}
      />

      <ConfirmationModal
        heading="Schedule Campaign?"
        body="Once you schedule your campaign, you’ll no longer be able to make any changes. If you need to update it, you’ll have to cancel this campaign and create a new one."
        buttons={[
          {
            label: "Confirm",
            semantic: Semantic.PRIMARY,
            onClick: handleSubmit,
          },
          {
            label: "Cancel",
            semantic: Semantic.SECONDARY,
            onClick: closeConfirmation,
          },
        ]}
        dismissible={false}
      />

      <EducationModal
        dismissible={false}
        heading="New rules for bulk sending introduced by Google and Yahoo"
        buttons={[
          {
            semantic: Semantic.PRIMARY,
            label: "Schedule",
            onClick: onCloseEducation,
          },
        ]}
      >
        <Stack direction="column" spacing={1}>
          Due to new domain warming and email deliverability rules introduced by
          Google and Yahoo in February 2024, you might not be able to send to
          all your fans at once. If that&apos;s the case, we&apos;ll create a
          sending schedule for you.
          <Button
            type={ButtonType.LINK}
            size="xsmall"
            href={smartScheduleFindMoreURL}
            target="_blank"
            rel="noopener noreferrer"
            label="Find Out More"
          />
        </Stack>
      </EducationModal>
    </>
  );
};

export default EmailCampaignSchedulePage;
