import React, { useEffect, useState } from "react";
import {
  Input,
  KomiModalChildrenRenderProps,
  LoadingOverlay,
  Tabs,
  Tab,
  TabSection,
  TabView,
  TabViews,
  TalentButton,
  TextArea,
  Typography,
  useKomiModals,
} from "@komi-app/components";
import { Card, Checkbox, Col, Row } from "antd";
import DragDropContext from "components/DragDropContext";
import PortalComponent from "components/PortalComponent/PortalComponent";
import { Icon } from "components/Icon";
import DragDropButton from "components/Button/DragDropButton";
import FontSelector from "components/FontSelector/FontSelector";
import { ColorPickerInput } from "components/ColorPicker";
import { EdcmColorPickerInput } from "components/ColorPicker";
import { ArrayServices } from "utils/array";
import {
  Controller,
  FormProvider,
  UseFormRegisterReturn,
  useForm,
  useFormContext,
} from "react-hook-form";
import {
  useEcdmConfig,
  useEdcmPrivacyPolicy,
} from "pages/AudienceAndCampaigns/Pages/Embed/utils";
import {
  EdcmDataCaptureFormField,
  EdcmDataCaptureMethod,
} from "@komi-app/edcm-sdk";
import { EdcmOptionalId } from "models/edcm/edcm";
import { EmbedDcm } from "@komi-app/edcm-ui";
import "@komi-app/edcm-ui/dist/esm/index.css";

import "components/DataCaptureAudience/DataCaptureCreationModal.scss";
import "./EmbedDcmSetup.scss";
import { Paragraph } from "components/Typography";
import { FLAGS, useFeatureIsOn } from "@komi-app/flags-sdk";

const stepComponents = [ContentStep, DataCaptureStep, CustomisationStep];

export function useEmbedDcmSetupModa() {
  const modals = useKomiModals();

  return {
    open(edcmId: string | undefined) {
      modals.open({
        title: "Website Embed",
        hasCloseButton: true,
        hasHeaderDivider: true,
        maxWidth: "1026px",
        children: ({ close, patch }) => (
          <EmbedDcmSetup close={close} patch={patch} edcmId={edcmId} />
        ),
      });
    },
  };
}

interface EmbedDcmSetupProps extends KomiModalChildrenRenderProps {
  edcmId: string | undefined;
}

const EmbedDcmSetup = ({ close, patch, edcmId }: EmbedDcmSetupProps) => {
  const { edcmConfig, saveEdcmConfig } = useEcdmConfig(edcmId);

  const { mutateAsync, isLoading: isSaving } = saveEdcmConfig;

  async function handleSave(updatedConfig: EdcmOptionalId) {
    await mutateAsync(
      {
        ...updatedConfig,
        borderRadius: Number(updatedConfig.borderRadius),
      },
      {
        onSuccess: close,
      }
    );
  }

  function handleClose() {
    close();
  }

  if (edcmConfig.isLoading) {
    return (
      <LoadingOverlay loading variant="light">
        <div className="height--320"></div>
      </LoadingOverlay>
    );
  } else if (!edcmConfig.data) {
    return <div>Error</div>;
  }

  return (
    <EmbedForm
      defaultValues={edcmConfig.data}
      onSave={handleSave}
      isSaving={isSaving}
      onClose={handleClose}
      patch={patch}
    />
  );
};

export default EmbedDcmSetup;

interface EmbedFormProps {
  defaultValues: EdcmOptionalId;
  onSave: (config: EdcmOptionalId) => any;
  isSaving?: boolean;
  onClose: () => any;
  patch: KomiModalChildrenRenderProps["patch"];
}

function EmbedForm({
  defaultValues,
  patch,
  onSave,
  onClose,
  isSaving,
}: EmbedFormProps) {
  const [step, setStep] = useState(0);

  const [showPreviewToast, setShowPreviewToast] = useState(true);

  useEffect(() => {
    patch({
      steps: {
        current: step + 1,
        max: stepComponents.length,
      },
    });
  }, [step]);

  const useFormResult = useForm({
    defaultValues,
    mode: "onChange",
  });

  const { watch, getValues, trigger } = useFormResult;

  function handlePreviousStep() {
    if (step === 0) {
      return onClose();
    }

    setStep(step - 1);
  }

  const lastStepSubmitted = step === stepComponents.length - 1;

  async function handleNextStep() {
    const isValid = await trigger();

    if (isValid) {
      if (lastStepSubmitted) {
        onSave(getValues());

        return;
      }

      setStep(step + 1);
    }
  }

  const Step = stepComponents[step];

  const privacyPolicy = useEdcmPrivacyPolicy();

  return (
    <div data-testid="embed_website_edit_modal" className="m__t--24">
      <div>
        <Row>
          <Col span={12} className="p__r--24">
            <FormProvider {...useFormResult}>
              <form>
                <Step />
              </form>
            </FormProvider>
          </Col>
          <Col span={12}>
            <Card bodyStyle={{ padding: 0 }}>
              <TabSection>
                <Tabs className="p__y--16 p__x--24 full-width">
                  <Tab
                    label="DEFAULT"
                    value="default"
                    style={{
                      width: "100%",
                    }}
                  />
                  <Tab
                    label="SUCCESS"
                    value="success"
                    style={{
                      width: "100%",
                    }}
                  />
                </Tabs>
                <div className="embed-setup--preview">
                  {showPreviewToast ? (
                    <div className="embed-setup--preview-toast">
                      <div>
                        <span className="embed-setup--preview-toast-info">
                          <svg
                            width="18"
                            height="18"
                            viewBox="0 0 18 18"
                            fill="none"
                            xmlns="http://www.w3.org/2000/svg"
                          >
                            <path
                              fillRule="evenodd"
                              clipRule="evenodd"
                              d="M9 18C13.9706 18 18 13.9706 18 9C18 4.02944 13.9706 0 9 0C4.02944 0 0 4.02944 0 9C0 13.9706 4.02944 18 9 18ZM9.75 4.5C9.75 4.91421 9.41421 5.25 9 5.25C8.58579 5.25 8.25 4.91421 8.25 4.5C8.25 4.08579 8.58579 3.75 9 3.75C9.41421 3.75 9.75 4.08579 9.75 4.5ZM8.25 7.5C8.25 7.08579 8.58579 6.75 9 6.75C9.41421 6.75 9.75 7.08579 9.75 7.5V13.5C9.75 13.9142 9.41421 14.25 9 14.25C8.58579 14.25 8.25 13.9142 8.25 13.5V7.5Z"
                              fill="#121212"
                            />
                          </svg>
                        </span>

                        <span className="embed-setup--preview-toast-text">
                          This is an interactive preview
                        </span>
                        <span
                          className="embed-setup--preview-toast-close"
                          onClick={() => setShowPreviewToast(false)}
                        >
                          <svg
                            width="12"
                            height="12"
                            viewBox="0 0 12 12"
                            fill="none"
                            xmlns="http://www.w3.org/2000/svg"
                          >
                            <path
                              id="Vector"
                              fillRule="evenodd"
                              clipRule="evenodd"
                              d="M0.229221 0.229221C0.534848 -0.0764069 1.03037 -0.0764069 1.336 0.229221L6 4.89322L10.664 0.229221C10.9696 -0.0764069 11.4652 -0.0764069 11.7708 0.229221C12.0764 0.534848 12.0764 1.03037 11.7708 1.336L7.10678 6L11.7708 10.664C12.0764 10.9696 12.0764 11.4652 11.7708 11.7708C11.4652 12.0764 10.9696 12.0764 10.664 11.7708L6 7.10678L1.336 11.7708C1.03037 12.0764 0.534848 12.0764 0.229221 11.7708C-0.0764069 11.4652 -0.0764069 10.9696 0.229221 10.664L4.89322 6L0.229221 1.336C-0.0764069 1.03037 -0.0764069 0.534848 0.229221 0.229221Z"
                              fill="#121212"
                            />
                          </svg>
                        </span>
                      </div>
                    </div>
                  ) : null}
                  <TabViews className="full-width">
                    <TabView value="default" className="full-width">
                      <EmbedDcm
                        id="edcm-setup-full-preview"
                        previewMode={true}
                        {...watch()}
                        privacyPolicy={privacyPolicy}
                      />
                    </TabView>
                    <TabView value="success" className="full-width">
                      <EmbedDcm
                        id="edcm-setup-success-preview"
                        previewMode={true}
                        previewSuccess={true}
                        {...watch()}
                        privacyPolicy={privacyPolicy}
                      />
                    </TabView>
                  </TabViews>
                </div>
              </TabSection>
            </Card>
          </Col>
        </Row>
      </div>
      <div className="email-domain-setup-modal-info-step__actions flex justify__content--end gap--16 m__t--24">
        <TalentButton variant="secondary" onClick={handlePreviousStep}>
          {step === 0 ? "Cancel" : "Previous"}
        </TalentButton>
        <TalentButton
          variant="primary"
          onClick={handleNextStep}
          disabled={step === 2 && isSaving}
        >
          {step === 2 ? (isSaving ? "Saving..." : "Done") : "Next"}
        </TalentButton>
      </div>
    </div>
  );
}

function ContentStep() {
  const { register } = useFormContext();

  return (
    <Card>
      <Paragraph preset="semibold18">Content</Paragraph>

      <ControlledInput
        register={register("title", {
          required: "Enter form title",
        })}
        label="Title"
        placeholder="E.g. “Subscribe to get my latest updates”"
      />

      <div className="p__t--16" />
      <TextArea
        register={register("description")}
        label="Description (optional)"
        placeholder="E.g. “Receive news, announcements and much more”"
        className="embed-setup--description"
      />

      <ControlledInput
        register={register("successMessage", {
          required: "Enter success message",
        })}
        label="Success message"
        placeholder="E.g. “You signed up successfully”"
      />
    </Card>
  );
}

function ControlledInput({
  label,
  placeholder,
  register,
  suffixText,
  type = "text",
}: {
  label: string;
  placeholder?: string;
  register: UseFormRegisterReturn<string>;
  suffixText?: string;
  type?: string;
}) {
  return (
    <Controller
      {...register}
      render={({ field, fieldState }) => (
        <Input
          {...field}
          // NOTE: toString is there to prevent the number 0 to e displayed as empty field
          value={field.value.toString()}
          onValueChange={(value) => {
            const parsedValue = type === "number" ? Number(value) : value;
            field.onChange(parsedValue);
          }}
          error={fieldState.error?.message}
          groupClassName="p__t--16"
          label={label}
          placeholder={placeholder}
          suffixText={suffixText}
          type={type}
        />
      )}
    />
  );
}

function DataCaptureStep() {
  const { register } = useFormContext();

  return (
    <>
      <Card className="signup-methods-card" data-testid="signup-methods-card">
        <span className="title">Signup Methods</span>
        <DataCaptureMethodsSelector register={register("dataCaptureMethods")} />
      </Card>

      <Card
        className="contact-data-card m__t--24"
        data-testid="contact-data-card"
      >
        <span className="title">Additional contact data to collect</span>
        <AdditionalCaptureMethodsSelector
          register={register("additionalCaptureMethods")}
        />
      </Card>
    </>
  );
}

function DataCaptureMethodsSelector({
  register,
}: {
  register: UseFormRegisterReturn<string>;
}) {
  return (
    <Controller
      {...register}
      render={({ field }) => (
        <DragDropContext
          droppableId="methods-drop"
          listClassName="method-list"
          itemIdPrefix="method"
          direction="vertical"
          list={field.value}
          onDropEndCallback={(list) => field.onChange(list)}
        >
          {(dragProvided, snapshot, item: EdcmDataCaptureMethod, linkIndex) => (
            <PortalComponent
              key={linkIndex}
              innerRef={dragProvided.innerRef}
              namespaceClass="method-list"
              provided={dragProvided}
              snapshot={snapshot}
              single={false}
            >
              <Row
                data-testid={item.label}
                className="additional-contact-method-row"
                align="middle"
              >
                <Col className="label" span={20}>
                  {item.label}
                </Col>
                <Col span={2}>
                  <div
                    className="visible-toggle"
                    onClick={() =>
                      field.onChange(
                        ArrayServices.updateWithIndex(field.value, linkIndex, {
                          ...field.value[linkIndex],
                          isVisible: !field.value[linkIndex].isVisible,
                        })
                      )
                    }
                  >
                    <Icon name={item.isVisible ? "open-eye" : "closed-eye"} />
                  </div>
                </Col>
                <Col span={2}>
                  <DragDropButton
                    dragType="vertical"
                    dragHandleProps={dragProvided.dragHandleProps || undefined}
                  />
                </Col>
              </Row>
            </PortalComponent>
          )}
        </DragDropContext>
      )}
    />
  );
}

function AdditionalCaptureMethodsSelector({
  register,
}: {
  register: UseFormRegisterReturn<string>;
}) {
  return (
    <Controller
      {...register}
      render={({ field }) => (
        <DragDropContext
          droppableId="methods-drop"
          listClassName="method-list"
          itemIdPrefix="method"
          direction="vertical"
          list={field.value}
          onDropEndCallback={field.onChange}
        >
          {(
            dragProvided,
            snapshot,
            item: EdcmDataCaptureFormField,
            linkIndex
          ) => (
            <PortalComponent
              key={linkIndex}
              innerRef={dragProvided.innerRef}
              namespaceClass="method-list"
              provided={dragProvided}
              snapshot={snapshot}
              single={false}
            >
              <Row
                data-testid={linkIndex}
                className="additional-contact-method-row"
                align="middle"
              >
                <Col className="label" span={14}>
                  {item.label}
                </Col>
                <Col span={6}>
                  <Checkbox
                    // label="Required"
                    checked={item.isRequired}
                    onChange={() =>
                      field.onChange(
                        ArrayServices.updateWithIndex(field.value, linkIndex, {
                          ...field.value[linkIndex],
                          isRequired: !field.value[linkIndex].isRequired,
                        })
                      )
                    }
                  >
                    Required
                  </Checkbox>
                </Col>
                <Col span={2}>
                  {item.isVisible ? (
                    <div
                      className="visible-toggle flex"
                      onClick={() =>
                        field.onChange(
                          ArrayServices.updateWithIndex(
                            field.value,
                            linkIndex,
                            {
                              ...field.value[linkIndex],
                              isVisible: !field.value[linkIndex].isVisible,
                            }
                          )
                        )
                      }
                    >
                      <Icon name="open-eye" />
                    </div>
                  ) : (
                    <div
                      className="visible-toggle flex"
                      onClick={() =>
                        field.onChange(
                          ArrayServices.updateWithIndex(
                            field.value,
                            linkIndex,
                            {
                              ...field.value[linkIndex],
                              isVisible: !field.value[linkIndex].isVisible,
                            }
                          )
                        )
                      }
                    >
                      <Icon name="closed-eye" />
                    </div>
                  )}
                </Col>
                <Col span={2}>
                  <DragDropButton
                    dragType="vertical"
                    dragHandleProps={dragProvided.dragHandleProps || undefined}
                  />
                </Col>
              </Row>
            </PortalComponent>
          )}
        </DragDropContext>
      )}
    />
  );
}

function CustomisationStep() {
  const { register } = useFormContext();

  return (
    <Card>
      <Paragraph preset="semibold18">Customize Appearance</Paragraph>

      <div className="m__t--16">
        <ControlledColorPickerInput
          title="Text and icons"
          register={register("textAndIconColor", {
            validate: (color) => validateColor(color, "Add color value"),
          })}
        />
      </div>

      <div className="m__t--16">
        <ControlledColorPickerInput
          title="Background"
          register={register("backgroundColor", {
            validate: (color) => validateColor(color, "Add color value"),
          })}
        />
      </div>

      <div className="m__t--16">
        <ControlledColorPickerInput
          title="Button text"
          register={register("buttonTextColor", {
            required: "Add color value",
          })}
        />
      </div>

      <div className="m__t--16">
        <ControlledColorPickerInput
          title="Button background"
          register={register("buttonBackgroundColor", {
            validate: (color) => validateColor(color, "Add color value"),
          })}
        />
      </div>

      <Typography.Body level={2} className="p__t--16">
        <label>Font</label>
      </Typography.Body>
      <ControlledFontSelector register={register("font")} />
      <ControlledInput
        type="number"
        register={register("borderRadius", {
          // NOTE: because of valueAsNumber, strings are considered empty values
          // so we send a invalid error message instead of required
          required: "Invalid radius value",
          valueAsNumber: true,

          validate: (num) => {
            if (num < 0) {
              return "Invalid radius value";
            }

            if (num % 1 !== 0) {
              return "Invalid radius value";
            }
          },
        })}
        label="Border radius"
        suffixText="px"
      />
    </Card>
  );
}

function ControlledColorPickerInput({
  register,
  title,
}: {
  title: string;
  register: UseFormRegisterReturn<string>;
}) {
  const isUsingDropdown = useFeatureIsOn(
    FLAGS.FEAT_CAC_305_EDCM
  );

  return (
    <Controller
      {...register}
      render={({ field, fieldState }) => (
        isUsingDropdown ? (
          <EdcmColorPickerInput
            value={field.value}
            onChange={(color) => field.onChange(color)}
            errorMessage={fieldState.error?.message}
            title={title}
            className="m__t--4"
          />
        ) : (
          <ColorPickerInput
            value={field.value}
            onChange={(color) => field.onChange(color)}
            errorMessage={fieldState.error?.message}
            title={title}
            className="m__t--4"
          />
        )
      )}
    />
  );
}

function ControlledFontSelector({
  register,
}: {
  register: UseFormRegisterReturn<string>;
}) {
  return (
    <Controller
      {...register}
      render={({ field }) => (
        <FontSelector
          value={field.value}
          onChange={(value) => field.onChange(value)}
        />
      )}
    />
  );
}

function validateColor(value: string, message: string): string | undefined {
  if (value === "" || value === "#") {
    return message;
  }

  return undefined;
}

interface PreviewProps {
  config: EdcmOptionalId;
}

function Preview({}: PreviewProps) {
  return null;
}
