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

import { Fragment, useEffect, useCallback, useLayoutEffect, useRef, useState, type RefObject } from "react";
import { observer } from "mobx-react";
import Link from "next/link";
import { createPortal } from "react-dom";
// icons
import { CirclePlus, LogOut, Mails } from "lucide-react";
// ui
import { Menu, Transition } from "@headlessui/react";
// plane imports
import { useTranslation } from "@plane/i18n";
import { ChevronDownIcon } from "@plane/propel/icons";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import type { IWorkspace } from "@plane/types";
import { Loader } from "@plane/ui";
import { orderWorkspacesList, cn } from "@plane/utils";
// helpers
import { AppSidebarItem } from "@/components/sidebar/sidebar-item";
// hooks
import { useAppTheme } from "@/hooks/store/use-app-theme";
import { useWorkspace } from "@/hooks/store/use-workspace";
import { useUser, useUserProfile } from "@/hooks/store/user";
import { useInstance } from "@/hooks/store/use-instance";
// components
import { WorkspaceLogo } from "../logo";
import SidebarDropdownItem from "./dropdown-item";

type WorkspaceMenuRootProps = {
  variant: "sidebar" | "top-navigation" | "sidebar-panel";
};

type WorkspaceMenuStateSyncProps = {
  open: boolean;
  variant: WorkspaceMenuRootProps["variant"];
  sidebarPanelButtonRef: RefObject<HTMLButtonElement | null>;
  onSidebarDropdownToggle: (value: boolean) => void;
  onSidebarPanelPositionChange: (position: { left: number; top: number; width: number } | null) => void;
};

function WorkspaceMenuStateSync(props: WorkspaceMenuStateSyncProps) {
  const { open, variant, sidebarPanelButtonRef, onSidebarDropdownToggle, onSidebarPanelPositionChange } = props;

  const updateSidebarPanelMenuPosition = useCallback(() => {
    if (variant !== "sidebar-panel" || !sidebarPanelButtonRef.current || typeof window === "undefined") return;

    const rect = sidebarPanelButtonRef.current.getBoundingClientRect();
    const width = 480;
    const viewportPadding = 16;

    onSidebarPanelPositionChange({
      left: Math.min(rect.left, window.innerWidth - width - viewportPadding),
      top: rect.bottom + 8,
      width,
    });
  }, [onSidebarPanelPositionChange, sidebarPanelButtonRef, variant]);

  useEffect(() => {
    onSidebarDropdownToggle(open);
  }, [onSidebarDropdownToggle, open]);

  useLayoutEffect(() => {
    if (!open || variant !== "sidebar-panel") {
      onSidebarPanelPositionChange(null);
      return;
    }

    updateSidebarPanelMenuPosition();

    const handlePositionUpdate = () => updateSidebarPanelMenuPosition();
    window.addEventListener("resize", handlePositionUpdate);
    window.addEventListener("scroll", handlePositionUpdate, true);

    return () => {
      window.removeEventListener("resize", handlePositionUpdate);
      window.removeEventListener("scroll", handlePositionUpdate, true);
    };
  }, [onSidebarPanelPositionChange, open, updateSidebarPanelMenuPosition, variant]);

  return null;
}

export const WorkspaceMenuRoot = observer(function WorkspaceMenuRoot(props: WorkspaceMenuRootProps) {
  const { variant } = props;
  // store hooks
  const { toggleSidebar, toggleAnySidebarDropdown } = useAppTheme();
  const { config } = useInstance();
  const { data: currentUser } = useUser();
  const { signOut } = useUser();
  const { updateUserProfile } = useUserProfile();
  const { currentWorkspace: activeWorkspace, workspaces } = useWorkspace();
  // derived values
  const isWorkspaceCreationDisabled = config?.is_workspace_creation_disabled ?? false;
  // translation
  const { t } = useTranslation();
  // local state
  const [sidebarPanelMenuPosition, setSidebarPanelMenuPosition] = useState<{
    left: number;
    top: number;
    width: number;
  } | null>(null);

  const sidebarPanelButtonRef = useRef<HTMLButtonElement>(null);

  const handleWorkspaceNavigation = (workspace: IWorkspace) => updateUserProfile({ last_workspace_id: workspace?.id });

  const handleSignOut = async () => {
    await signOut().catch(() =>
      setToast({
        type: TOAST_TYPE.ERROR,
        title: t("sign_out.toast.error.title"),
        message: t("sign_out.toast.error.message"),
      })
    );
  };

  const handleItemClick = () => {
    if (window.innerWidth < 768) {
      toggleSidebar();
    }
  };
  const workspacesList = orderWorkspacesList(Object.values(workspaces ?? {}));
  // TODO: fix workspaces list scroll

  return (
    <Menu
      as="div"
      className={cn("relative z-20 flex h-full w-fit max-w-48 whitespace-nowrap overflow-visible", {
        "w-full justify-center text-center": variant === "sidebar",
        "flex-grow justify-stretch text-left": variant === "top-navigation",
        "w-full max-w-none justify-stretch text-left": variant === "sidebar-panel",
      })}
    >
      {({ open, close }: { open: boolean; close: () => void }) => {
        return (
          <>
            <WorkspaceMenuStateSync
              open={open}
              variant={variant}
              sidebarPanelButtonRef={sidebarPanelButtonRef}
              onSidebarDropdownToggle={toggleAnySidebarDropdown}
              onSidebarPanelPositionChange={setSidebarPanelMenuPosition}
            />
            {variant === "sidebar" && (
              <Menu.Button
                className={cn("flex size-8 w-full items-center justify-center rounded-md", {
                  "bg-layer-1": open,
                })}
              >
                <AppSidebarItem
                  variant="button"
                  item={{
                    icon: (
                      <WorkspaceLogo
                        logo={activeWorkspace?.logo_url}
                        name={activeWorkspace?.name}
                        classNames="size-8 rounded-md border border-subtle"
                      />
                    ),
                  }}
                />
              </Menu.Button>
            )}
            {variant === "top-navigation" && (
              <Menu.Button
                className={cn(
                  "group/menu-button flex flex-grow items-center justify-between gap-1 truncate rounded-sm p-1 text-13 font-medium text-secondary hover:bg-layer-1 focus:outline-none",
                  {
                    "bg-layer-1": open,
                  }
                )}
                aria-label={t("aria_labels.projects_sidebar.open_workspace_switcher")}
              >
                <div className="flex flex-grow items-center gap-2 truncate">
                  <WorkspaceLogo
                    logo={activeWorkspace?.logo_url}
                    name={activeWorkspace?.name}
                    classNames="border border-subtle rounded-md size-7"
                  />
                  <h4 className="truncate text-14 font-medium text-primary">{activeWorkspace?.name ?? t("loading")}</h4>
                </div>
                <ChevronDownIcon
                  className={cn("size-4 flex-shrink-0 text-placeholder duration-300", {
                    "rotate-180": open,
                  })}
                />
              </Menu.Button>
            )}
            {variant === "sidebar-panel" && (
              <Menu.Button
                ref={sidebarPanelButtonRef}
                className={cn(
                  "group/menu-button flex w-full items-center justify-between gap-2 px-0 py-1 text-left text-13 font-medium text-secondary transition-all focus:outline-none",
                  {
                    "text-primary": open,
                  }
                )}
                aria-label={t("aria_labels.projects_sidebar.open_workspace_switcher")}
              >
                <div className="flex min-w-0 flex-1 items-center gap-2.5 truncate">
                  <WorkspaceLogo
                    logo={activeWorkspace?.logo_url}
                    name={activeWorkspace?.name}
                    classNames="size-8 rounded-[0.9rem]"
                  />
                  <div className="min-w-0 flex-1">
                    <h4 className="truncate text-14 font-medium text-primary">
                      {activeWorkspace?.name ?? t("loading")}
                    </h4>
                  </div>
                </div>
                <ChevronDownIcon
                  className={cn("size-4 flex-shrink-0 text-placeholder duration-300", {
                    "rotate-180": open,
                  })}
                />
              </Menu.Button>
            )}
            {(() => {
              const menuItems = (
                <Menu.Items
                  as="div"
                  className={cn(
                    "z-21 mt-1 flex min-w-[30rem] origin-top-left flex-col divide-y overflow-hidden outline-none",
                    {
                      "fixed divide-subtle rounded-md border-[0.5px] border-strong bg-surface-1 shadow-raised-200":
                        variant !== "sidebar-panel",
                      "top-11 left-14": variant === "sidebar",
                      "top-10 left-4": variant === "top-navigation",
                      "nodedc-glass-modal nodedc-glass-popup-surface rounded-[1.5rem] divide-white/10":
                        variant === "sidebar-panel",
                    }
                  )}
                  style={
                    variant === "sidebar-panel" && sidebarPanelMenuPosition
                      ? {
                          position: "fixed",
                          left: `${sidebarPanelMenuPosition.left}px`,
                          top: `${sidebarPanelMenuPosition.top}px`,
                          width: `${sidebarPanelMenuPosition.width}px`,
                        }
                      : undefined
                  }
                >
                  <div className="vertical-scrollbar flex scrollbar-sm max-h-96 flex-col items-start justify-start overflow-x-hidden overflow-y-scroll">
                    <span
                      className={cn(
                        "sticky top-0 z-21 h-full w-full flex-shrink-0 truncate px-4 pt-3 pb-1 text-left text-13 font-medium text-placeholder",
                        {
                          "rounded-md bg-surface-1": variant !== "sidebar-panel",
                          "bg-transparent": variant === "sidebar-panel",
                        }
                      )}
                    >
                      {currentUser?.email}
                    </span>
                    {workspacesList ? (
                      <div className="flex size-full flex-col items-start justify-start">
                        {(activeWorkspace
                          ? [
                              activeWorkspace,
                              ...workspacesList.filter((workspace) => workspace.id !== activeWorkspace?.id),
                            ]
                          : workspacesList
                        ).map((workspace) => (
                          <SidebarDropdownItem
                            key={workspace.id}
                            workspace={workspace}
                            activeWorkspace={activeWorkspace}
                            handleItemClick={handleItemClick}
                            handleWorkspaceNavigation={handleWorkspaceNavigation}
                            handleClose={close}
                          />
                        ))}
                      </div>
                    ) : (
                      <div className="w-full">
                        <Loader className="space-y-2">
                          <Loader.Item height="30px" />
                          <Loader.Item height="30px" />
                        </Loader>
                      </div>
                    )}
                  </div>
                  <div className="flex w-full flex-col items-start justify-start gap-2 px-4 py-2 text-13">
                    {!isWorkspaceCreationDisabled && (
                      <Link href="/create-workspace" className="w-full">
                        <Menu.Item
                          as="div"
                          className="flex items-center gap-2 rounded-xl px-2 py-1.5 text-13 font-medium text-secondary hover:bg-layer-transparent-hover"
                        >
                          <CirclePlus className="size-4 flex-shrink-0" />
                          {t("create_workspace")}
                        </Menu.Item>
                      </Link>
                    )}

                    <Link href="/invitations" className="w-full" onClick={handleItemClick}>
                      <Menu.Item
                        as="div"
                        className="flex items-center gap-2 rounded-xl px-2 py-1.5 text-13 font-medium text-secondary hover:bg-layer-transparent-hover"
                      >
                        <Mails className="h-4 w-4 flex-shrink-0" />
                        {t("workspace_invites")}
                      </Menu.Item>
                    </Link>

                    <div className="w-full">
                      <Menu.Item
                        as="button"
                        type="button"
                        className="flex w-full items-center gap-2 rounded-xl px-2 py-1.5 text-13 font-medium text-danger-primary hover:bg-layer-transparent-hover"
                        onClick={handleSignOut}
                      >
                        <LogOut className="size-4 flex-shrink-0" />
                        {t("sign_out")}
                      </Menu.Item>
                    </div>
                  </div>
                </Menu.Items>
              );

              if (variant === "sidebar-panel") {
                if (!open || !sidebarPanelMenuPosition || typeof document === "undefined") return null;
                return createPortal(menuItems, document.body);
              }

              return (
                <Transition
                  as={Fragment}
                  enter="transition ease-out duration-100"
                  enterFrom="transform opacity-0 scale-95"
                  enterTo="trnsform opacity-100 scale-100"
                  leave="transition ease-in duration-75"
                  leaveFrom="transform opacity-100 scale-100"
                  leaveTo="transform opacity-0 scale-95"
                >
                  {menuItems}
                </Transition>
              );
            })()}
          </>
        );
      }}
    </Menu>
  );
});
