/**
 * Copyright (c) 2023-present Plane Software, Inc. and contributors
 * SPDX-License-Identifier: AGPL-3.0-only
 * See the LICENSE file for details.
 */

import { useEffect, useState } from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { Controller, useForm } from "react-hook-form";

// types
import { SPACE_BASE_PATH, SPACE_BASE_URL } from "@plane/constants";
import { Button } from "@plane/propel/button";
import { GlobeIcon, NewTabIcon, CheckIcon } from "@plane/propel/icons";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import type { TProjectPublishLayouts, TProjectPublishSettings } from "@plane/types";
// ui
import { Loader, ToggleSwitch, CustomSelect, ModalCore, EModalWidth } from "@plane/ui";
// helpers
import { copyTextToClipboard } from "@plane/utils";
// hooks
import { useProjectPublish } from "@/hooks/store/use-project-publish";

type Props = {
  isOpen: boolean;
  projectId: string;
  onClose: () => void;
};

const defaultValues: Partial<TProjectPublishSettings> = {
  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 = observer(function PublishProjectModal(props: Props) {
  const { isOpen, onClose, projectId } = props;
  // states
  const [isUnPublishing, setIsUnPublishing] = useState(false);
  // router
  const { workspaceSlug } = useParams();
  // store hooks
  const {
    fetchPublishSettings,
    getPublishSettingsByProjectID,
    publishProject,
    updatePublishSettings,
    unPublishProject,
    fetchSettingsLoader,
  } = useProjectPublish();
  // derived values
  const projectPublishSettings = getPublishSettingsByProjectID(projectId);
  const isProjectPublished = !!projectPublishSettings?.anchor;
  // 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(), projectId);
    }
  }, [fetchPublishSettings, isOpen, projectId, projectPublishSettings, workspaceSlug]);

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

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

    await updatePublishSettings(workspaceSlug.toString(), projectId, 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(), projectId, 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<TProjectPublishSettings>) => {
    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<TProjectPublishSettings> = {
      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 && isProjectPublished) 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 SPACE_APP_URL = (SPACE_BASE_URL.trim() === "" ? window.location.origin : SPACE_BASE_URL) + SPACE_BASE_PATH;
  const publishLink = `${SPACE_APP_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-18 font-medium text-secondary">Publish project</h5>
          {isProjectPublished && (
            <Button
              variant="error-fill"
              size="lg"
              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="space-y-4 px-5">
            {isProjectPublished && projectPublishSettings && (
              <>
                <div className="flex items-center justify-between gap-2 rounded-md border border-strong py-1.5 pr-1 pl-4">
                  <a
                    href={publishLink}
                    className="truncate text-13 text-secondary"
                    target="_blank"
                    rel="noopener noreferrer"
                  >
                    {publishLink}
                  </a>
                  <div className="flex flex-shrink-0 items-center gap-1">
                    <a
                      href={publishLink}
                      className="grid size-8 place-items-center rounded-sm bg-layer-3 hover:bg-layer-3-hover"
                      target="_blank"
                      rel="noopener noreferrer"
                    >
                      <NewTabIcon className="size-4" />
                    </a>
                    <button
                      type="button"
                      className="h-8 rounded-sm bg-layer-3 px-3 py-2 text-11 font-medium hover:bg-layer-3-hover"
                      onClick={handleCopyLink}
                    >
                      Copy link
                    </button>
                  </div>
                </div>
                <p className="mt-3 flex items-center gap-1 text-13 font-medium text-accent-primary">
                  <span className="relative grid size-2.5 place-items-center">
                    <span className="absolute inline-flex size-full animate-ping rounded-full bg-accent-primary opacity-75" />
                    <span className="relative inline-flex size-1.5 rounded-full bg-accent-primary" />
                  </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-13">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) && <CheckIcon className="size-3.5 flex-shrink-0" />}
                        </CustomSelect.Option>
                      ))}
                    </CustomSelect>
                  )}
                />
              </div>
              <div className="relative flex items-center justify-between gap-2">
                <div className="text-13">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-13">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-13">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 mt-4 flex items-center justify-between border-t border-subtle px-5 py-4">
          <div className="flex items-center gap-1 text-13 text-placeholder">
            <GlobeIcon className="size-3.5" />
            <div className="text-13">Anyone with the link can access</div>
          </div>
          {!fetchSettingsLoader && (
            <div className="relative flex items-center gap-2">
              <Button variant="secondary" size="lg" onClick={handleClose}>
                Cancel
              </Button>
              {isProjectPublished ? (
                isDirty && (
                  <Button variant="primary" size="lg" type="submit" loading={isSubmitting}>
                    {isSubmitting ? "Updating" : "Update settings"}
                  </Button>
                )
              ) : (
                <Button variant="primary" size="lg" type="submit" loading={isSubmitting}>
                  {isSubmitting ? "Publishing" : "Publish"}
                </Button>
              )}
            </div>
          )}
        </div>
      </form>
    </ModalCore>
  );
});
