import React, { useEffect, useState, useRef, useCallback } from "react";
import Image from "next/image";
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
import useSWR from "swr";
import { useDropzone } from "react-dropzone";
import { Tab, Popover } from "@headlessui/react";
import { Control, Controller } from "react-hook-form";
// hooks
import { useApplication, useWorkspace } from "hooks/store";
import { useDropdownKeyDown } from "hooks/use-dropdown-key-down";
// services
import { FileService } from "services/file.service";
// hooks
import useOutsideClickDetector from "hooks/use-outside-click-detector";
// components
import { Button, Input, Loader } from "@plane/ui";
// constants
import { MAX_FILE_SIZE } from "constants/common";

const tabOptions = [
  {
    key: "unsplash",
    title: "Unsplash",
  },
  {
    key: "images",
    title: "Images",
  },
  {
    key: "upload",
    title: "Upload",
  },
];

type Props = {
  label: string | React.ReactNode;
  value: string | null;
  control: Control<any>;
  onChange: (data: string) => void;
  disabled?: boolean;
  tabIndex?: number;
};

// services
const fileService = new FileService();

export const ImagePickerPopover: React.FC<Props> = observer((props) => {
  const { label, value, control, onChange, disabled = false, tabIndex } = props;
  // states
  const [image, setImage] = useState<File | null>(null);
  const [isImageUploading, setIsImageUploading] = useState(false);
  const [isOpen, setIsOpen] = useState(false);
  const [searchParams, setSearchParams] = useState("");
  const [formData, setFormData] = useState({
    search: "",
  });
  // refs
  const ref = useRef<HTMLDivElement>(null);
  // router
  const router = useRouter();
  const { workspaceSlug } = router.query;
  // store hooks
  const {
    config: { envConfig },
  } = useApplication();
  const { currentWorkspace } = useWorkspace();

  const { data: unsplashImages, error: unsplashError } = useSWR(
    `UNSPLASH_IMAGES_${searchParams}`,
    () => fileService.getUnsplashImages(searchParams),
    {
      revalidateOnFocus: false,
      revalidateOnReconnect: false,
    }
  );

  const { data: projectCoverImages } = useSWR(`PROJECT_COVER_IMAGES`, () => fileService.getProjectCoverImages(), {
    revalidateOnFocus: false,
    revalidateOnReconnect: false,
  });

  const imagePickerRef = useRef<HTMLDivElement>(null);

  const onDrop = useCallback((acceptedFiles: File[]) => {
    setImage(acceptedFiles[0]);
  }, []);

  const { getRootProps, getInputProps, isDragActive, fileRejections } = useDropzone({
    onDrop,
    accept: {
      "image/*": [".png", ".jpg", ".jpeg", ".svg", ".webp"],
    },
    maxSize: envConfig?.file_size_limit ?? MAX_FILE_SIZE,
  });

  const handleSubmit = async () => {
    setIsImageUploading(true);

    if (!image || !workspaceSlug) return;

    const formData = new FormData();
    formData.append("asset", image);
    formData.append("attributes", JSON.stringify({}));

    fileService
      .uploadFile(workspaceSlug.toString(), formData)
      .then((res) => {
        const oldValue = value;
        const isUnsplashImage = oldValue?.split("/")[2] === "images.unsplash.com";

        const imageUrl = res.asset;
        onChange(imageUrl);
        setIsImageUploading(false);
        setImage(null);
        setIsOpen(false);

        if (isUnsplashImage) return;

        if (oldValue && currentWorkspace) fileService.deleteFile(currentWorkspace.id, oldValue);
      })
      .catch((err) => {
        console.error(err);
      });
  };

  useEffect(() => {
    if (!unsplashImages || value !== null) return;

    onChange(unsplashImages[0].urls.regular);
  }, [value, onChange, unsplashImages]);

  const handleClose = () => {
    if (isOpen) setIsOpen(false);
  };

  const toggleDropdown = () => {
    setIsOpen((prevIsOpen) => !prevIsOpen);
  };

  const handleKeyDown = useDropdownKeyDown(toggleDropdown, handleClose);

  const handleOnClick = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
    e.stopPropagation();
    e.preventDefault();
    toggleDropdown();
  };

  useOutsideClickDetector(ref, handleClose);

  return (
    <Popover className="relative z-[2]" ref={ref} tabIndex={tabIndex} onKeyDown={handleKeyDown}>
      <Popover.Button
        className="rounded border border-custom-border-300 bg-custom-background-100 px-2 py-1 text-xs text-custom-text-200 hover:text-custom-text-100"
        onClick={handleOnClick}
        disabled={disabled}
      >
        {label}
      </Popover.Button>

      {isOpen && (
        <Popover.Panel
          className="absolute right-0 z-10 mt-2 rounded-md border border-custom-border-200 bg-custom-background-100 shadow-custom-shadow-sm"
          static
        >
          <div
            ref={imagePickerRef}
            className="flex h-96 w-80 flex-col overflow-auto rounded border border-custom-border-300 bg-custom-background-100 p-3 shadow-2xl md:h-[28rem] md:w-[36rem]"
          >
            <Tab.Group>
              <Tab.List as="span" className="inline-block rounded bg-custom-background-80 p-1">
                {tabOptions.map((tab) => {
                  if (!unsplashImages && unsplashError && tab.key === "unsplash") return null;
                  if (projectCoverImages && projectCoverImages.length === 0 && tab.key === "images") return null;

                  return (
                    <Tab
                      key={tab.key}
                      className={({ selected }) =>
                        `rounded px-4 py-1 text-center text-sm outline-none transition-colors ${
                          selected ? "bg-custom-primary text-white" : "text-custom-text-100"
                        }`
                      }
                    >
                      {tab.title}
                    </Tab>
                  );
                })}
              </Tab.List>
              <Tab.Panels className="h-full w-full flex-1 overflow-y-auto overflow-x-hidden">
                {(unsplashImages || !unsplashError) && (
                  <Tab.Panel className="mt-4 h-full w-full space-y-4">
                    <div className="flex gap-x-2">
                      <Controller
                        control={control}
                        name="search"
                        render={({ field: { value, ref } }) => (
                          <Input
                            id="search"
                            name="search"
                            type="text"
                            value={value}
                            onChange={(e) => setFormData({ ...formData, search: e.target.value })}
                            ref={ref}
                            placeholder="Search for images"
                            className="w-full text-sm"
                          />
                        )}
                      />
                      <Button variant="primary" onClick={() => setSearchParams(formData.search)} size="sm">
                        Search
                      </Button>
                    </div>
                    {unsplashImages ? (
                      unsplashImages.length > 0 ? (
                        <div className="grid grid-cols-4 gap-4">
                          {unsplashImages.map((image) => (
                            <div
                              key={image.id}
                              className="relative col-span-2 aspect-video md:col-span-1"
                              onClick={() => {
                                setIsOpen(false);
                                onChange(image.urls.regular);
                              }}
                            >
                              <img
                                src={image.urls.small}
                                alt={image.alt_description}
                                className="absolute left-0 top-0 h-full w-full cursor-pointer rounded object-cover"
                              />
                            </div>
                          ))}
                        </div>
                      ) : (
                        <p className="pt-7 text-center text-xs text-custom-text-300">No images found.</p>
                      )
                    ) : (
                      <Loader className="grid grid-cols-4 gap-4">
                        <Loader.Item height="80px" width="100%" />
                        <Loader.Item height="80px" width="100%" />
                        <Loader.Item height="80px" width="100%" />
                        <Loader.Item height="80px" width="100%" />
                        <Loader.Item height="80px" width="100%" />
                        <Loader.Item height="80px" width="100%" />
                        <Loader.Item height="80px" width="100%" />
                        <Loader.Item height="80px" width="100%" />
                      </Loader>
                    )}
                  </Tab.Panel>
                )}
                {(!projectCoverImages || projectCoverImages.length !== 0) && (
                  <Tab.Panel className="mt-4 h-full w-full space-y-4">
                    {projectCoverImages ? (
                      projectCoverImages.length > 0 ? (
                        <div className="grid grid-cols-4 gap-4">
                          {projectCoverImages.map((image, index) => (
                            <div
                              key={image}
                              className="relative col-span-2 aspect-video md:col-span-1"
                              onClick={() => {
                                setIsOpen(false);
                                onChange(image);
                              }}
                            >
                              <img
                                src={image}
                                alt={`Default project cover image- ${index}`}
                                className="absolute left-0 top-0 h-full w-full cursor-pointer rounded object-cover"
                              />
                            </div>
                          ))}
                        </div>
                      ) : (
                        <p className="pt-7 text-center text-xs text-custom-text-300">No images found.</p>
                      )
                    ) : (
                      <Loader className="grid grid-cols-4 gap-4 pt-4">
                        <Loader.Item height="80px" width="100%" />
                        <Loader.Item height="80px" width="100%" />
                        <Loader.Item height="80px" width="100%" />
                        <Loader.Item height="80px" width="100%" />
                        <Loader.Item height="80px" width="100%" />
                        <Loader.Item height="80px" width="100%" />
                        <Loader.Item height="80px" width="100%" />
                        <Loader.Item height="80px" width="100%" />
                      </Loader>
                    )}
                  </Tab.Panel>
                )}
                <Tab.Panel className="mt-4 h-full w-full">
                  <div className="flex h-full w-full flex-col gap-y-2">
                    <div className="flex w-full flex-1 items-center gap-3">
                      <div
                        {...getRootProps()}
                        className={`relative grid h-full w-full cursor-pointer place-items-center rounded-lg p-12 text-center focus:outline-none focus:ring-2 focus:ring-custom-primary focus:ring-offset-2 ${
                          (image === null && isDragActive) || !value
                            ? "border-2 border-dashed border-custom-border-200 hover:bg-custom-background-90"
                            : ""
                        }`}
                      >
                        <button
                          type="button"
                          className="absolute right-0 top-0 z-40 -translate-y-1/2 rounded bg-custom-background-90 px-2 py-0.5 text-xs font-medium text-custom-text-200"
                        >
                          Edit
                        </button>
                        {image !== null || (value && value !== "") ? (
                          <>
                            <Image
                              layout="fill"
                              objectFit="cover"
                              src={image ? URL.createObjectURL(image) : value ? value : ""}
                              alt="image"
                              className="rounded-lg"
                            />
                          </>
                        ) : (
                          <div>
                            <span className="mt-2 block text-sm font-medium text-custom-text-200">
                              {isDragActive ? "Drop image here to upload" : "Drag & drop image here"}
                            </span>
                          </div>
                        )}

                        <input {...getInputProps()} type="text" />
                      </div>
                    </div>
                    {fileRejections.length > 0 && (
                      <p className="text-sm text-red-500">
                        {fileRejections[0].errors[0].code === "file-too-large"
                          ? "The image size cannot exceed 5 MB."
                          : "Please upload a file in a valid format."}
                      </p>
                    )}

                    <p className="text-sm text-custom-text-200">
                      File formats supported- .jpeg, .jpg, .png, .webp, .svg
                    </p>

                    <div className="flex h-12 items-start justify-end gap-2">
                      <Button
                        variant="neutral-primary"
                        onClick={() => {
                          setIsOpen(false);
                          setImage(null);
                        }}
                      >
                        Cancel
                      </Button>
                      <Button
                        variant="primary"
                        className="w-full"
                        onClick={handleSubmit}
                        disabled={!image}
                        loading={isImageUploading}
                      >
                        {isImageUploading ? "Uploading..." : "Upload & Save"}
                      </Button>
                    </div>
                  </div>
                </Tab.Panel>
              </Tab.Panels>
            </Tab.Group>
          </div>
        </Popover.Panel>
      )}
    </Popover>
  );
});