import { useEffect, useState } from "react";
import { observer } from "mobx-react";
import { useRouter } from "next/router";
import { Controller, useForm } from "react-hook-form";
import { Check, ExternalLink, Globe2 } from "lucide-react";
// types
import { IProject, TProjectPublishLayouts, TPublishSettings } from "@plane/types";
// ui
import { Button, Loader, ToggleSwitch, TOAST_TYPE, setToast, CustomSelect } from "@plane/ui";
// components
import { EModalWidth, ModalCore } from "@/components/core";
// helpers
import { SPACE_BASE_URL } from "@/helpers/common.helper";
import { copyTextToClipboard } from "@/helpers/string.helper";
// hooks
import { useProjectPublish } from "@/hooks/store";

type Props = {
  isOpen: boolean;
  project: IProject;
  onClose: () => void;
};

const defaultValues: Partial<TPublishSettings> = {
  is_comments_enabled: false,
  is_reactions_enabled: false,
  is_votes_enabled: false,
  inbox: null,
  view_props: {
    list: true,
    kanban: true,
  },
};

const VIEW_OPTIONS: {
  key: TProjectPublishLayouts;
  label: string;
}[] = [
  { key: "list", label: "List" },
  { key: "kanban", label: "Kanban" },
];

export const PublishProjectModal: React.FC<Props> = observer((props) => {
  const { isOpen, project, onClose } = props;
  // states
  const [isUnPublishing, setIsUnPublishing] = useState(false);
  // router
  const router = useRouter();
  const { workspaceSlug } = router.query;
  // store hooks
  const {
    fetchPublishSettings,
    getPublishSettingsByProjectID,
    publishProject,
    updatePublishSettings,
    unPublishProject,
    fetchSettingsLoader,
  } = useProjectPublish();
  // derived values
  const projectPublishSettings = getPublishSettingsByProjectID(project.id);
  // form info
  const {
    control,
    formState: { isDirty, isSubmitting },
    handleSubmit,
    reset,
    watch,
  } = useForm({
    defaultValues,
  });

  const handleClose = () => {
    onClose();
  };

  // fetch publish settings
  useEffect(() => {
    if (!workspaceSlug || !isOpen) return;

    if (!projectPublishSettings) {
      fetchPublishSettings(workspaceSlug.toString(), project.id);
    }
  }, [fetchPublishSettings, isOpen, project, projectPublishSettings, workspaceSlug]);

  const handlePublishProject = async (payload: Partial<TPublishSettings>) => {
    if (!workspaceSlug) return;
    await publishProject(workspaceSlug.toString(), project.id, payload);
  };

  const handleUpdatePublishSettings = async (payload: Partial<TPublishSettings>) => {
    if (!workspaceSlug || !payload.id) return;

    await updatePublishSettings(workspaceSlug.toString(), project.id, payload.id, payload).then((res) => {
      setToast({
        type: TOAST_TYPE.SUCCESS,
        title: "Success!",
        message: "Publish settings updated successfully!",
      });

      handleClose();
      return res;
    });
  };

  const handleUnPublishProject = async (publishId: string) => {
    if (!workspaceSlug || !publishId) return;

    setIsUnPublishing(true);

    await unPublishProject(workspaceSlug.toString(), project.id, publishId)
      .catch(() =>
        setToast({
          type: TOAST_TYPE.ERROR,
          title: "Error!",
          message: "Something went wrong while unpublishing the project.",
        })
      )
      .finally(() => setIsUnPublishing(false));
  };

  const selectedLayouts = Object.entries(watch("view_props") ?? {})
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    .filter(([key, value]) => value)
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    .map(([key, value]) => key)
    .filter((l) => VIEW_OPTIONS.find((o) => o.key === l));

  const handleFormSubmit = async (formData: Partial<TPublishSettings>) => {
    if (!selectedLayouts || selectedLayouts.length === 0) {
      setToast({
        type: TOAST_TYPE.ERROR,
        title: "Error!",
        message: "Please select at least one view layout to publish the project.",
      });
      return;
    }

    const payload: Partial<TPublishSettings> = {
      id: formData.id,
      is_comments_enabled: formData.is_comments_enabled,
      is_reactions_enabled: formData.is_reactions_enabled,
      is_votes_enabled: formData.is_votes_enabled,
      view_props: formData.view_props,
    };

    if (formData.id && project.anchor) await handleUpdatePublishSettings(payload);
    else await handlePublishProject(payload);
  };

  // prefill form values for already published projects
  useEffect(() => {
    if (!projectPublishSettings?.anchor) return;

    reset({
      ...defaultValues,
      ...projectPublishSettings,
    });
  }, [projectPublishSettings, reset]);

  const publishLink = `${SPACE_BASE_URL}/issues/${projectPublishSettings?.anchor}`;

  const handleCopyLink = () =>
    copyTextToClipboard(publishLink).then(() =>
      setToast({
        type: TOAST_TYPE.SUCCESS,
        title: "",
        message: "Published page link copied successfully.",
      })
    );

  return (
    <ModalCore isOpen={isOpen} handleClose={handleClose} width={EModalWidth.XXL}>
      <form onSubmit={handleSubmit(handleFormSubmit)}>
        <div className="flex items-center justify-between gap-2 p-5">
          <h5 className="text-xl font-medium text-custom-text-200">Publish page</h5>
          {project.anchor && (
            <Button variant="danger" onClick={() => handleUnPublishProject(watch("id") ?? "")} loading={isUnPublishing}>
              {isUnPublishing ? "Unpublishing" : "Unpublish"}
            </Button>
          )}
        </div>

        {/* content */}
        {fetchSettingsLoader ? (
          <Loader className="space-y-4 px-5">
            <Loader.Item height="30px" />
            <Loader.Item height="30px" />
            <Loader.Item height="30px" />
            <Loader.Item height="30px" />
          </Loader>
        ) : (
          <div className="px-5 space-y-4">
            {project.anchor && projectPublishSettings && (
              <>
                <div className="bg-custom-background-80 border border-custom-border-300 rounded-md py-1.5 pl-4 pr-1 flex items-center justify-between gap-2">
                  <a
                    href={publishLink}
                    className="text-sm text-custom-text-200 truncate"
                    target="_blank"
                    rel="noopener noreferrer"
                  >
                    {publishLink}
                  </a>
                  <div className="flex-shrink-0 flex items-center gap-1">
                    <a
                      href={publishLink}
                      className="size-8 grid place-items-center bg-custom-background-90 hover:bg-custom-background-100 rounded"
                      target="_blank"
                      rel="noopener noreferrer"
                    >
                      <ExternalLink className="size-4" />
                    </a>
                    <button
                      type="button"
                      className="h-8 bg-custom-background-90 hover:bg-custom-background-100 rounded text-xs font-medium py-2 px-3"
                      onClick={handleCopyLink}
                    >
                      Copy link
                    </button>
                  </div>
                </div>
                <p className="text-sm font-medium text-custom-primary-100 flex items-center gap-1 mt-3">
                  <span className="relative grid place-items-center size-2.5">
                    <span className="animate-ping absolute inline-flex size-full rounded-full bg-custom-primary-100 opacity-75" />
                    <span className="relative inline-flex rounded-full size-1.5 bg-custom-primary-100" />
                  </span>
                  This project is now live on web
                </p>
              </>
            )}
            <div className="space-y-4">
              <div className="relative flex items-center justify-between gap-2">
                <div className="text-sm">Views</div>
                <Controller
                  control={control}
                  name="view_props"
                  render={({ field: { onChange, value } }) => (
                    <CustomSelect
                      value={value}
                      label={VIEW_OPTIONS.filter((o) => selectedLayouts.includes(o.key))
                        .map((o) => o.label)
                        .join(", ")}
                      onChange={(val: TProjectPublishLayouts) => {
                        if (selectedLayouts.length === 1 && selectedLayouts[0] === val) return;
                        onChange({
                          ...value,
                          [val]: !value?.[val],
                        });
                      }}
                      buttonClassName="border-none"
                      placement="bottom-end"
                    >
                      {VIEW_OPTIONS.map((option) => (
                        <CustomSelect.Option
                          key={option.key}
                          value={option.key}
                          className="flex items-center justify-between gap-2"
                        >
                          {option.label}
                          {selectedLayouts.includes(option.key) && <Check className="size-3.5 flex-shrink-0" />}
                        </CustomSelect.Option>
                      ))}
                    </CustomSelect>
                  )}
                />
              </div>
              <div className="relative flex items-center justify-between gap-2">
                <div className="text-sm">Allow comments</div>
                <Controller
                  control={control}
                  name="is_comments_enabled"
                  render={({ field: { onChange, value } }) => (
                    <ToggleSwitch value={!!value} onChange={onChange} size="sm" />
                  )}
                />
              </div>
              <div className="relative flex items-center justify-between gap-2">
                <div className="text-sm">Allow reactions</div>
                <Controller
                  control={control}
                  name="is_reactions_enabled"
                  render={({ field: { onChange, value } }) => (
                    <ToggleSwitch value={!!value} onChange={onChange} size="sm" />
                  )}
                />
              </div>
              <div className="relative flex items-center justify-between gap-2">
                <div className="text-sm">Allow voting</div>
                <Controller
                  control={control}
                  name="is_votes_enabled"
                  render={({ field: { onChange, value } }) => (
                    <ToggleSwitch value={!!value} onChange={onChange} size="sm" />
                  )}
                />
              </div>
            </div>
          </div>
        )}

        {/* modal handlers */}
        <div className="relative flex items-center justify-between border-t border-custom-border-200 px-5 py-4 mt-4">
          <div className="flex items-center gap-1 text-sm text-custom-text-400">
            <Globe2 className="size-3.5" />
            <div className="text-sm">Anyone with the link can access</div>
          </div>
          {!fetchSettingsLoader && (
            <div className="relative flex items-center gap-2">
              <Button variant="neutral-primary" size="sm" onClick={handleClose}>
                Cancel
              </Button>
              {project.anchor ? (
                isDirty && (
                  <Button variant="primary" size="sm" type="submit" loading={isSubmitting}>
                    {isSubmitting ? "Updating" : "Update settings"}
                  </Button>
                )
              ) : (
                <Button variant="primary" size="sm" type="submit" loading={isSubmitting}>
                  {isSubmitting ? "Publishing" : "Publish"}
                </Button>
              )}
            </div>
          )}
        </div>
      </form>
    </ModalCore>
  );
});