import React, { useMemo, useRef, useState } from "react";
import { Location } from "history";
import { Prompt, useLocation } from "react-router-dom";
import { Editor, EditorRef } from "react-email-editor";

import config from "config";

import {
  InlineMessage,
  Input,
  LoadingOverlay,
  TalentButton,
  useConfirmationModal,
} from "@komi-app/components";

import {
  CampaignTemplateCreateDto,
  TemplateAddressDto,
  TemplateDto,
} from "types/templates";
import { ClassicEditor, UnlayerDesign } from "types/unlayer";

import { TemplateBuilder } from "..";
import { ImportedTemplateEditor } from "..";

import { join } from "utils/string";
import { emptyAddress } from "../utils";
import { isClassicTemplate } from "../TemplateImport/guards";

import "./TemplateBuilderPage.scss";
import { FLAGS, useFeatureIsOn } from "@komi-app/flags-sdk";
import { useUnsavedChangesRedirectionWarning } from "hooks/useUnsavedChangesRedirectionWarning";

export interface TemplateBuilderPageProps
  extends React.HTMLProps<HTMLDivElement> {
  existingTemplate?: Partial<TemplateDto>;
  initialTemplate?: UnlayerDesign;
  isCampaignTemplate?: boolean;
  backButtonText: string;
  handleGoBack: () => void;
  handleCreateOrUpdateTemplate: (
    template: CampaignTemplateCreateDto,
  ) => Promise<boolean>;
  disablePrompt?: boolean;
}

export type TemplateCreateRouteState = {
  selectedTemplate?: Record<string, any>;
};

export const TemplateBuilderPage: React.FC<TemplateBuilderPageProps> = ({
  handleGoBack,
  handleCreateOrUpdateTemplate,
  isCampaignTemplate = false,
  existingTemplate,
  initialTemplate,
  backButtonText,
  disablePrompt = false,
}) => {
  const location = useLocation();
  const locationState = location.state as TemplateCreateRouteState;
  let selectedTemplate: Record<string, any> | undefined;
  if (locationState && locationState.selectedTemplate) {
    selectedTemplate = locationState.selectedTemplate;
  }
  const template =
    existingTemplate?.templateJson || selectedTemplate || initialTemplate;
  const isImportedTemplate = isClassicTemplate(template);

  const isExistingTemplate = useMemo(
    () => Boolean(existingTemplate),
    [existingTemplate],
  );
  const existingTemplateName = useMemo(
    () => existingTemplate?.name,
    [existingTemplate],
  );

  const [html, setHtml] = useState(() => {
    const initialHtml = isImportedTemplate
      ? template.html
      : existingTemplate?.templateHtml;

    return initialHtml || "";
  });
  const [templateName, setTemplateName] = useState(
    existingTemplate?.name || "",
  );
  const [nameError, showNameError] = useState(false);
  const [builderUpdated, setBuilderUpdated] = useState(!isExistingTemplate);
  const [isSaving, setIsSaving] = useState(false);
  const [isLoading, setIsLoading] = useState(true);
  const [isConfirming, setIsConfirming] = useState(false);

  const emailEditorRef = useRef<EditorRef>(null);
  const [emailEditor, setEmailEditor] = useState<ClassicEditor | Editor | null>(
    null,
  );

  const isTemplateImportFixEnabled = useFeatureIsOn(
    FLAGS.FIX_CAC_97_IMPORT_TEMPLATE_HTML,
  );
  const isUnsavedChangeRedirectionWarningOn = useFeatureIsOn(
    FLAGS.CRM_901_PREVIEW_LINKS_DISABLED,
  );

  const isUnsubscribeDeletable = useFeatureIsOn(
    FLAGS.FEAT_CRM_1267_ALLOW_DELETE_FOOTER,
  );

  // const [design, setDesign] = useState<Design>();
  const [address, setAddress] = useState<TemplateAddressDto>(emptyAddress());

  const confirmationModal = useConfirmationModal();
  isUnsavedChangeRedirectionWarningOn &&
    useUnsavedChangesRedirectionWarning(
      !isSaving && !isConfirming && builderUpdated,
    );

  const isUnsubscribeTagPresent = useMemo(() => {
    if (!isUnsubscribeDeletable)
      return isImportedTemplate && html.includes("{%unsubscribe%}");

    return (
      html.includes("{%unsubscribe%}") || html.includes("_unsubscribe_link_")
    );
  }, [html, isImportedTemplate, isUnsubscribeDeletable]);

  // Check if there is an svg image in the template and disable saving if so
  const isSvgPresent = useMemo(() => {
    const parser = new DOMParser();
    const doc = parser.parseFromString(html, "text/html");
    const svgElements = doc.querySelectorAll("svg");
    return svgElements.length > 0;
  }, [html]);

  const isTemplateNameValid = (templateName: string) => {
    return templateName && templateName.trim() !== "";
  };

  const isSavingEnabled = useMemo(() => {
    // Conditions to meet to disable saving button:
    // - If the name is invalid
    if (!isTemplateNameValid(templateName)) return false;

    // - If an svg image is present
    if (isSvgPresent) return false;

    // - If a template has no unsubscribe tag
    if (
      !isUnsubscribeTagPresent &&
      (isImportedTemplate || isUnsubscribeDeletable)
    ) {
      return false;
    }

    // Conditions to meet to enable saving button:
    // - If the template does not exist
    if (!existingTemplate) return true;
    // - If the existing template has updates
    if (builderUpdated) return true;
    // - If an existing template has no updates and the name has changed
    if (existingTemplateName !== templateName) return true;

    return false; // By default, enable the save button
  }, [
    existingTemplate,
    isUnsubscribeTagPresent,
    templateName,
    builderUpdated,
    isSvgPresent,
    isUnsubscribeDeletable,
  ]);

  const upsertTemplate = async (template: CampaignTemplateCreateDto) => {
    const success = await handleCreateOrUpdateTemplate(template);

    setIsLoading(false);

    if (!success) return;

    setBuilderUpdated(false);
    setIsSaving(false);
  };

  const onSaveButtonClicked = async () => {
    if (!isTemplateNameValid(templateName)) {
      return showNameError(true);
    }

    setIsSaving(true);
    setBuilderUpdated(false);

    if (!emailEditor || !html) return;

    setIsLoading(true);

    if (isImportedTemplate) {
      // Ensure the template is saved with the correct html
      const templateJson = isTemplateImportFixEnabled
        ? {
            classic: true,
            html,
          }
        : template;

      // We can add the icon as the template thumbnail here.
      return upsertTemplate({
        name: templateName,
        templateJson,
        thumbnailUrl: `${config.service.assetUrl}/assets/images/template-placeholder.svg`,
        templateHtml: html,
        address,
      });
    }

    emailEditor.exportImage(async function (data) {
      return upsertTemplate({
        name: templateName,
        templateJson: data.design,
        thumbnailUrl: data.url,
        templateHtml: html,
        address,
      });
    });
  };

  const handleDesignUpdated = () => {
    setBuilderUpdated(true);
  };

  const handleNameChange = (updatedName: string) => {
    setTemplateName(updatedName);
    setBuilderUpdated(true);
    showNameError(false);
  };

  const handleHtmlChange = (updatedHtml: string) => {
    setHtml(updatedHtml);
    setBuilderUpdated(true);
  };

  const confirmNavigate = (location: Location) => {
    setIsConfirming(true);

    confirmationModal.open({
      className: isPromptFixOn ? "confirmation-modal-template" : undefined,
      title: "Are you sure you want to leave this page?",
      description: "Any changes made to this template will be lost.",
      minWidth: "520px",
      onConfirm: async () => {
        window.location.href = location.pathname;
      },
      onCancel: () => {
        setIsConfirming(false);
      },
      buttons: [
        {
          label: "Leave",
          action: "confirm",
          variant: "primary",
        },
        {
          label: "Cancel",
          action: "cancel",
          variant: "secondary",
        },
      ],
    });
    return false;
  };

  const isPromptFixOn = useFeatureIsOn(
    FLAGS.FIX_CRM_83_TEMPLATE_SHOW_CONFIRM_PROMPT,
  );

  return (
    <>
      <LoadingOverlay variant="light" loading={isLoading}>
        <div className="template-builder-page">
          {!existingTemplate && (
            <InlineMessage
              type="info"
              closeable
              message={join(
                [
                  "Consider adding a business address in the footer to comply with the U.S. CAN-SPAM Act.",
                  !isImportedTemplate &&
                    "To do so, click on the footer block and enter your address.",
                ],
                " ",
              )}
            />
          )}
          {!isUnsubscribeTagPresent &&
            (isImportedTemplate || (html && isUnsubscribeDeletable)) && (
              <InlineMessage
                className="template-builder-page__unsubscribe-message"
                type="error"
                closeable
                message={
                  "The unsubscribe tag is missing. Add a link and use the {%unsubscribe%} tag as destination."
                }
              />
            )}
          {isSvgPresent && (
            <InlineMessage
              className="template-builder-page__error-message"
              type="error"
              closeable
              message={
                "SVG images are not supported. Please replace them with PNG or JPEG images."
              }
            />
          )}

          {isCampaignTemplate ? (
            <InlineMessage
              type="info"
              closeable
              message="Any changes made here would only affect this email"
            />
          ) : (
            <Input
              groupClassName="template-builder__name"
              className="template-builder__name-input"
              label="Template name"
              placeholder="Enter template name"
              value={templateName}
              onValueChange={handleNameChange}
              error={nameError ? "Template name is required" : undefined}
            />
          )}
          <div className="template-builder__builder">
            {isImportedTemplate ? (
              <ImportedTemplateEditor
                emailEditor={emailEditor as ClassicEditor}
                html={html}
                setHtml={handleHtmlChange}
                setIsLoading={setIsLoading}
                setEmailEditor={setEmailEditor}
              />
            ) : (
              <TemplateBuilder
                initialTemplate={template}
                onDesignUpdated={handleDesignUpdated}
                ref={emailEditorRef}
                setAddress={setAddress}
                setHtml={handleHtmlChange}
                setIsLoading={setIsLoading}
                setEmailEditor={(editor: Editor) => setEmailEditor(editor)}
              />
            )}
          </div>

          <div className="template-builder__controls">
            <TalentButton onClick={handleGoBack} variant="secondary">
              {backButtonText}
            </TalentButton>

            <TalentButton
              onClick={onSaveButtonClicked}
              variant="primary"
              disabled={!isSavingEnabled}
            >
              Save
            </TalentButton>
          </div>
        </div>
      </LoadingOverlay>
      {/**
       * Cannot have multiple prompts on the same page
       * Gives option to disable prompt
       * Component is reused in a modal and a page
       */}
      {!disablePrompt && (
        <Prompt when={!isSaving && builderUpdated} message={confirmNavigate} />
      )}
    </>
  );
};
