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

import React, { useEffect, useMemo, useRef, useState } from "react";
import { xor } from "lodash-es";
import { observer } from "mobx-react";
import { useTheme } from "next-themes";
import { Combobox } from "@headlessui/react";
// pi dash ui
import { useTranslation } from "@pi-dash/i18n";
import { Button } from "@pi-dash/propel/button";
import { Logo } from "@pi-dash/propel/emoji-icon-picker";
import { SearchIcon, CloseIcon } from "@pi-dash/propel/icons";
import { Checkbox, EModalPosition, EModalWidth, ModalCore } from "@pi-dash/ui";
import { cn } from "@pi-dash/utils";
// assets
import darkProjectAsset from "@/app/assets/empty-state/search/project-dark.webp?url";
import lightProjectAsset from "@/app/assets/empty-state/search/project-light.webp?url";
// components
import { SimpleEmptyState } from "@/components/empty-state/simple-empty-state-root";
// hooks
import { useProject } from "@/hooks/store/use-project";

type Props = {
  isOpen: boolean;
  onClose: () => void;
  selectedProjectIds: string[];
  projectIds: string[];
  onSubmit: (projectIds: string[]) => Promise<void>;
};

export const ProjectMultiSelectModal = observer(function ProjectMultiSelectModal(props: Props) {
  const { isOpen, onClose, selectedProjectIds: selectedProjectIdsProp, projectIds, onSubmit } = props;
  // states
  const [searchTerm, setSearchTerm] = useState("");
  const [selectedProjectIds, setSelectedProjectIds] = useState<string[]>([]);
  const [isSubmitting, setIsSubmitting] = useState(false);
  // refs
  const moveButtonRef = useRef<HTMLButtonElement>(null);
  // theme hook
  const { resolvedTheme } = useTheme();
  // pi dash hooks
  const { t } = useTranslation();
  // store hooks
  const { getProjectById } = useProject();
  // derived values
  const projectDetailsMap = useMemo(
    () => new Map(projectIds.map((id) => [id, getProjectById(id)])),
    [projectIds, getProjectById]
  );
  const areSelectedProjectsChanged = xor(selectedProjectIds, selectedProjectIdsProp).length > 0;
  const filteredProjectIds = projectIds.filter((id) => {
    const project = projectDetailsMap.get(id);
    const projectQuery = `${project?.identifier} ${project?.name}`.toLowerCase();
    return projectQuery.includes(searchTerm.toLowerCase());
  });
  const filteredProjectResolvedPath = resolvedTheme === "light" ? lightProjectAsset : darkProjectAsset;

  useEffect(() => {
    if (isOpen) setSelectedProjectIds(selectedProjectIdsProp);
  }, [isOpen, selectedProjectIdsProp]);

  const handleClose = () => {
    onClose();
    setTimeout(() => {
      setSearchTerm("");
      setSelectedProjectIds([]);
    }, 300);
  };

  const handleSubmit = async () => {
    setIsSubmitting(true);
    await onSubmit(selectedProjectIds);
    setIsSubmitting(false);
    handleClose();
  };

  const handleSelectedProjectChange = (val: string[]) => {
    setSelectedProjectIds(val);
    setSearchTerm("");
    moveButtonRef.current?.focus();
  };

  if (!isOpen) return null;

  return (
    <ModalCore isOpen={isOpen} width={EModalWidth.LG} position={EModalPosition.TOP} handleClose={handleClose}>
      <Combobox as="div" multiple value={selectedProjectIds} onChange={handleSelectedProjectChange}>
        <div className="flex items-center gap-2 border-b border-subtle px-4">
          <SearchIcon className="size-4 flex-shrink-0 text-placeholder" aria-hidden="true" />
          <Combobox.Input
            className="h-12 w-full border-0 bg-transparent text-13 text-primary outline-none placeholder:text-placeholder focus:ring-0"
            placeholder="Search for projects"
            displayValue={() => ""}
            value={searchTerm}
            onChange={(e) => setSearchTerm(e.target.value)}
          />
        </div>
        {selectedProjectIds.length > 0 && (
          <div className="flex flex-wrap gap-2 px-4 pt-2">
            {selectedProjectIds.map((projectId) => {
              const projectDetails = projectDetailsMap.get(projectId);
              if (!projectDetails) return null;
              return (
                <div
                  key={projectDetails.id}
                  className="group flex cursor-pointer items-center gap-1.5 rounded-sm bg-surface-2 px-2 py-1"
                  onClick={() => {
                    handleSelectedProjectChange(selectedProjectIds.filter((id) => id !== projectDetails.id));
                  }}
                >
                  <Logo logo={projectDetails.logo_props} size={14} />
                  <p className="truncate text-11 text-tertiary transition-colors group-hover:text-secondary">
                    {projectDetails.identifier}
                  </p>
                  <CloseIcon className="size-3 flex-shrink-0 text-placeholder transition-colors group-hover:text-secondary" />
                </div>
              );
            })}
          </div>
        )}
        <Combobox.Options
          static
          className="vertical-scrollbar scrollbar-md max-h-80 scroll-py-2 overflow-y-auto py-2 transition-[height] duration-200 ease-in-out"
        >
          {filteredProjectIds.length === 0 ? (
            <div className="flex flex-col items-center justify-center px-3 py-8 text-center">
              <SimpleEmptyState
                title={t("No matching projects")}
                description={t("No projects detected with the matching criteria. \n Create a new project instead.")}
                assetPath={filteredProjectResolvedPath}
              />
            </div>
          ) : (
            <ul
              className={cn("text-primary", {
                "px-2": filteredProjectIds.length > 0,
              })}
            >
              {filteredProjectIds.map((projectId) => {
                const projectDetails = projectDetailsMap.get(projectId);
                if (!projectDetails) return null;
                const isProjectSelected = selectedProjectIds.includes(projectDetails.id);
                return (
                  <Combobox.Option
                    key={projectDetails.id}
                    value={projectDetails.id}
                    className={({ active }) =>
                      cn(
                        "flex w-full cursor-pointer items-center justify-between gap-2 truncate rounded-md p-2 text-secondary transition-colors select-none",
                        {
                          "bg-layer-1": active,
                          "text-primary": isProjectSelected,
                        }
                      )
                    }
                  >
                    <div className="flex items-center gap-2 truncate">
                      <span className="flex flex-shrink-0 items-center gap-2.5">
                        <Checkbox checked={isProjectSelected} />
                        <Logo logo={projectDetails.logo_props} size={16} />
                      </span>
                      <span className="flex-shrink-0 text-10">{projectDetails.identifier}</span>
                      <p className="truncate text-13">{projectDetails.name}</p>
                    </div>
                  </Combobox.Option>
                );
              })}
            </ul>
          )}
        </Combobox.Options>
      </Combobox>
      <div className="flex items-center justify-end gap-2 border-t border-subtle p-3">
        <Button variant="secondary" size="lg" onClick={handleClose}>
          {t("Cancel")}
        </Button>
        <Button
          ref={moveButtonRef}
          variant="primary"
          size="lg"
          onClick={handleSubmit}
          loading={isSubmitting}
          disabled={!areSelectedProjectsChanged}
        >
          {isSubmitting ? t("Confirming") : t("Confirm")}
        </Button>
      </div>
    </ModalCore>
  );
});
