import React, { useState, useEffect } from "react";

import Image from "next/image";
import { useRouter } from "next/router";

import useSWR, { mutate } from "swr";

import { useForm, Controller } from "react-hook-form";

import { Dialog, Transition } from "@headlessui/react";

// services
import projectServices from "services/project.service";
import workspaceService from "services/workspace.service";
// hooks
import useToast from "hooks/use-toast";
// ui
import { PrimaryButton } from "components/ui/button/primary-button";
import { Button, Input, TextArea, CustomSelect } from "components/ui";
// icons
import { XMarkIcon } from "@heroicons/react/24/outline";
// components
import { ImagePickerPopover } from "components/core";
import EmojiIconPicker from "components/emoji-icon-picker";
// helpers
import { getRandomEmoji } from "helpers/common.helper";
// types
import { IProject } from "types";
// fetch-keys
import { PROJECTS_LIST, WORKSPACE_MEMBERS_ME } from "constants/fetch-keys";
// constants
import { NETWORK_CHOICES } from "constants/project";

type Props = {
  isOpen: boolean;
  setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
};

const defaultValues: Partial<IProject> = {
  name: "",
  identifier: "",
  description: "",
  network: 2,
  icon: getRandomEmoji(),
  cover_image: null,
};

const IsGuestCondition: React.FC<{
  setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
}> = ({ setIsOpen }) => {
  const { setToastAlert } = useToast();

  useEffect(() => {
    setIsOpen(false);
    setToastAlert({
      title: "Error",
      type: "error",
      message: "You don't have permission to create project.",
    });
  }, [setIsOpen, setToastAlert]);

  return null;
};

export const CreateProjectModal: React.FC<Props> = (props) => {
  const { isOpen, setIsOpen } = props;

  const [isChangeIdentifierRequired, setIsChangeIdentifierRequired] = useState(true);

  const { setToastAlert } = useToast();

  const {
    query: { workspaceSlug },
  } = useRouter();

  const { data: myWorkspaceMembership } = useSWR(
    workspaceSlug ? WORKSPACE_MEMBERS_ME(workspaceSlug as string) : null,
    workspaceSlug ? () => workspaceService.workspaceMemberMe(workspaceSlug as string) : null,
    {
      shouldRetryOnError: false,
    }
  );

  const {
    register,
    formState: { errors, isSubmitting },
    handleSubmit,
    reset,
    setError,
    control,
    watch,
    setValue,
  } = useForm<IProject>({
    defaultValues,
    mode: "all",
    reValidateMode: "onChange",
  });

  const projectName = watch("name") ?? "";
  const projectIdentifier = watch("identifier") ?? "";

  useEffect(() => {
    if (projectName && isChangeIdentifierRequired)
      setValue("identifier", projectName.replace(/ /g, "").toUpperCase().substring(0, 3));
  }, [projectName, projectIdentifier, setValue, isChangeIdentifierRequired]);

  useEffect(() => () => setIsChangeIdentifierRequired(true), [isOpen]);

  const handleClose = () => {
    setIsOpen(false);
    reset(defaultValues);
  };

  const onSubmit = async (formData: IProject) => {
    if (!workspaceSlug) return;
    await projectServices
      .createProject(workspaceSlug as string, formData)
      .then((res) => {
        mutate<IProject[]>(
          PROJECTS_LIST(workspaceSlug as string),
          (prevData) => [res, ...(prevData ?? [])],
          false
        );
        setToastAlert({
          title: "Success",
          type: "success",
          message: "Project created successfully",
        });
        handleClose();
      })
      .catch((err) => {
        if (err.status === 403) {
          setToastAlert({
            title: "Error",
            type: "error",
            message: "You don't have permission to create project.",
          });
          handleClose();
          return;
        }
        err = err.data;
        Object.keys(err).map((key) => {
          const errorMessages = err[key];
          setError(key as keyof IProject, {
            message: Array.isArray(errorMessages) ? errorMessages.join(", ") : errorMessages,
          });
        });
      });
  };

  // FIXME: remove this and authorize using getServerSideProps
  if (myWorkspaceMembership && isOpen) {
    if (myWorkspaceMembership.role <= 10) return <IsGuestCondition setIsOpen={setIsOpen} />;
  }

  return (
    <Transition.Root show={isOpen} as={React.Fragment}>
      <Dialog as="div" className="relative z-20" onClose={handleClose}>
        <Transition.Child
          as={React.Fragment}
          enter="ease-out duration-300"
          enterFrom="opacity-0"
          enterTo="opacity-100"
          leave="ease-in duration-200"
          leaveFrom="opacity-100"
          leaveTo="opacity-0"
        >
          <div className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
        </Transition.Child>

        <div className="fixed inset-0 z-20 overflow-y-auto">
          <div className="flex min-h-full items-center justify-center p-4 text-center sm:p-0">
            <Transition.Child
              as={React.Fragment}
              enter="ease-out duration-300"
              enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
              enterTo="opacity-100 translate-y-0 sm:scale-100"
              leave="ease-in duration-200"
              leaveFrom="opacity-100 translate-y-0 sm:scale-100"
              leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
            >
              <Dialog.Panel className="transform rounded-lg bg-white text-left shadow-xl transition-all sm:w-full sm:max-w-2xl">
                <div className="relative h-36 w-full rounded-t-lg bg-gray-300">
                  {watch("cover_image") !== null && (
                    <Image
                      src={watch("cover_image")!}
                      layout="fill"
                      alt="cover image"
                      objectFit="cover"
                      className="rounded-t-lg"
                    />
                  )}

                  <div className="absolute right-2 top-2 p-2">
                    <button type="button" onClick={handleClose}>
                      <XMarkIcon className="h-5 w-5 text-white" />
                    </button>
                  </div>
                  <div className="absolute bottom-0 left-0 flex w-full justify-between px-6 py-5">
                    <div className="absolute left-0 bottom-0 h-16 w-full bg-gradient-to-t from-black opacity-60" />
                    <h3 className="z-[1] text-xl text-white">Create Project</h3>
                    <div>
                      <ImagePickerPopover
                        label="Change Cover"
                        onChange={(image) => {
                          setValue("cover_image", image);
                        }}
                        value={watch("cover_image")}
                      />
                    </div>
                  </div>
                </div>
                <form onSubmit={handleSubmit(onSubmit)}>
                  <div className="mt-5 space-y-4 px-4 py-3">
                    <div className="flex items-center gap-x-2">
                      <div>
                        <EmojiIconPicker
                          label={String.fromCodePoint(parseInt(watch("icon")))}
                          onChange={(emoji) => {
                            setValue("icon", emoji);
                          }}
                          value={watch("icon")}
                        />
                      </div>

                      <div className="flex-shrink-0 flex-grow">
                        <Input
                          id="name"
                          name="name"
                          type="name"
                          placeholder="Enter name"
                          error={errors.name}
                          register={register}
                          className="text-xl"
                          mode="transparent"
                          validations={{
                            required: "Name is required",
                            maxLength: {
                              value: 255,
                              message: "Name should be less than 255 characters",
                            },
                          }}
                        />
                      </div>
                    </div>

                    <div>
                      <Input
                        id="identifier"
                        name="identifier"
                        type="text"
                        mode="transparent"
                        className="text-sm"
                        placeholder="Enter Project Identifier"
                        error={errors.identifier}
                        register={register}
                        onChange={() => setIsChangeIdentifierRequired(false)}
                        validations={{
                          required: "Identifier is required",
                          validate: (value) =>
                            /^[A-Z]+$/.test(value) || "Identifier must be uppercase text.",
                          minLength: {
                            value: 1,
                            message: "Identifier must at least be of 1 character",
                          },
                          maxLength: {
                            value: 5,
                            message: "Identifier must at most be of 5 characters",
                          },
                        }}
                      />
                    </div>

                    <div>
                      <TextArea
                        id="description"
                        name="description"
                        mode="transparent"
                        className="text-sm"
                        placeholder="Enter description"
                        error={errors.description}
                        register={register}
                      />
                    </div>

                    <div className="w-40">
                      <Controller
                        name="network"
                        control={control}
                        render={({ field: { onChange, value } }) => (
                          <CustomSelect
                            value={value}
                            onChange={onChange}
                            label={
                              Object.keys(NETWORK_CHOICES).find((k) => k === value.toString())
                                ? NETWORK_CHOICES[value.toString() as keyof typeof NETWORK_CHOICES]
                                : "Select network"
                            }
                            input
                          >
                            {Object.keys(NETWORK_CHOICES).map((key) => (
                              <CustomSelect.Option key={key} value={key}>
                                {NETWORK_CHOICES[key as keyof typeof NETWORK_CHOICES]}
                              </CustomSelect.Option>
                            ))}
                          </CustomSelect>
                        )}
                      />
                    </div>
                  </div>

                  <div className="mt-5 flex justify-end gap-2 border-t-2 px-4 py-3">
                    <Button theme="secondary" onClick={handleClose}>
                      Cancel
                    </Button>
                    <PrimaryButton type="submit" size="sm" loading={isSubmitting}>
                      {isSubmitting ? "Adding project..." : "Add Project"}
                    </PrimaryButton>
                  </div>
                </form>
              </Dialog.Panel>
            </Transition.Child>
          </div>
        </div>
      </Dialog>
    </Transition.Root>
  );
};