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

import { createPortal } from "react-dom";
import { useCallback, useEffect, useRef, useState, type MouseEvent as ReactMouseEvent, type ReactNode } from "react";
import { observer } from "mobx-react";
import { cn } from "@plane/utils";
import type { TExternalContourRequest, TNameDescriptionLoader } from "@plane/types";
import useKeypress from "@/hooks/use-keypress";
import usePeekOverviewOutsideClickDetector from "@/hooks/use-peek-overview-outside-click";
import { ExternalContoursIssueActionsHeader, type TExternalContourPeekMode } from "./issue-header";

const SIDE_PEEK_WIDTH_STORAGE_KEY = "nodedc:external-contour-peek-width";
const SIDE_PEEK_MIN_WIDTH = 780;

type Props = {
  workspaceSlug: string;
  projectId: string;
  contourRequest: TExternalContourRequest;
  hasDirectTargetAccess: boolean;
  isSubmitting: TNameDescriptionLoader;
  embedIssue?: boolean;
  embedRemoveCurrentNotification?: () => void;
  children: ReactNode;
  onClose: () => void;
};

export const ExternalContoursPeekShell = observer(function ExternalContoursPeekShell(props: Props) {
  const {
    workspaceSlug,
    projectId,
    contourRequest,
    hasDirectTargetAccess,
    isSubmitting,
    embedIssue = false,
    embedRemoveCurrentNotification,
    children,
    onClose,
  } = props;
  const [peekMode, setPeekMode] = useState<TExternalContourPeekMode>("side-peek");
  const [sidePeekWidth, setSidePeekWidth] = useState<number>(() => {
    if (typeof window === "undefined") return SIDE_PEEK_MIN_WIDTH;

    const fallbackWidth = Math.max(SIDE_PEEK_MIN_WIDTH, Math.floor(window.innerWidth * 0.54));
    const storedWidth = window.localStorage.getItem(SIDE_PEEK_WIDTH_STORAGE_KEY);
    const parsedWidth = storedWidth ? parseInt(storedWidth, 10) : NaN;

    return Number.isFinite(parsedWidth) ? parsedWidth : fallbackWidth;
  });
  const [isResizingPeek, setIsResizingPeek] = useState(false);

  const issuePeekOverviewRef = useRef<HTMLDivElement>(null);
  const initialPeekWidthRef = useRef<number>(0);
  const initialMouseXRef = useRef<number>(0);

  const removeRoutePeekId = useCallback(() => {
    if (embedIssue) {
      embedRemoveCurrentNotification?.();
      return;
    }

    onClose();
  }, [embedIssue, embedRemoveCurrentNotification, onClose]);

  const stopPeekResizing = useCallback(() => {
    setIsResizingPeek(false);
  }, []);

  const handlePeekResize = useCallback(
    (event: MouseEvent) => {
      if (!isResizingPeek) return;

      const maxWidth = Math.max(SIDE_PEEK_MIN_WIDTH, window.innerWidth - 48);
      const deltaX = event.clientX - initialMouseXRef.current;
      const nextWidth = Math.min(Math.max(initialPeekWidthRef.current - deltaX, SIDE_PEEK_MIN_WIDTH), maxWidth);
      setSidePeekWidth(nextWidth);
    },
    [isResizingPeek]
  );

  const startPeekResizing = useCallback(
    (event: ReactMouseEvent) => {
      if (peekMode !== "side-peek") return;
      event.preventDefault();
      setIsResizingPeek(true);
      initialPeekWidthRef.current = sidePeekWidth;
      initialMouseXRef.current = event.clientX;
    },
    [peekMode, sidePeekWidth]
  );

  useEffect(() => {
    const handleWindowResize = () => {
      const maxWidth = Math.max(SIDE_PEEK_MIN_WIDTH, window.innerWidth - 48);
      setSidePeekWidth((currentWidth) => Math.min(currentWidth, maxWidth));
    };

    window.addEventListener("resize", handleWindowResize);
    return () => window.removeEventListener("resize", handleWindowResize);
  }, []);

  useEffect(() => {
    if (typeof window === "undefined") return;

    const maxWidth = Math.max(SIDE_PEEK_MIN_WIDTH, window.innerWidth - 48);
    const clampedWidth = Math.min(Math.max(sidePeekWidth, SIDE_PEEK_MIN_WIDTH), maxWidth);

    window.localStorage.setItem(SIDE_PEEK_WIDTH_STORAGE_KEY, String(clampedWidth));

    if (clampedWidth !== sidePeekWidth) {
      setSidePeekWidth(clampedWidth);
    }
  }, [sidePeekWidth]);

  useEffect(() => {
    if (!isResizingPeek) return;

    document.addEventListener("mousemove", handlePeekResize);
    document.addEventListener("mouseup", stopPeekResizing);
    document.addEventListener("mouseleave", stopPeekResizing);
    window.addEventListener("blur", stopPeekResizing);
    document.body.style.cursor = "col-resize";
    document.body.style.userSelect = "none";

    return () => {
      document.removeEventListener("mousemove", handlePeekResize);
      document.removeEventListener("mouseup", stopPeekResizing);
      document.removeEventListener("mouseleave", stopPeekResizing);
      window.removeEventListener("blur", stopPeekResizing);
      document.body.style.cursor = "";
      document.body.style.userSelect = "";
    };
  }, [handlePeekResize, isResizingPeek, stopPeekResizing]);

  usePeekOverviewOutsideClickDetector(
    issuePeekOverviewRef,
    () => {
      if (!embedIssue) removeRoutePeekId();
    },
    contourRequest.id,
    ["main-sidebar"]
  );

  useKeypress("Escape", () => !embedIssue && removeRoutePeekId());

  const peekOverviewClassName = cn(
    !embedIssue
      ? "absolute z-[25] flex flex-col overflow-hidden border border-subtle/70 bg-surface-1/80 backdrop-blur-2xl transition-all duration-300"
      : "h-full w-full",
    !embedIssue && {
      "top-3 right-3 bottom-3 w-[calc(100%-1.5rem)] rounded-[28px] border md:min-w-[780px] md:max-w-[calc(100vw-1.5rem)]":
        peekMode === "side-peek",
      "top-[8.33%] left-[8.33%] size-5/6 rounded-[28px]": peekMode === "modal",
      "absolute inset-0 m-4 rounded-[28px]": peekMode === "full-screen",
    }
  );

  const portalContainer = typeof document !== "undefined" ? document.getElementById("full-screen-portal") : null;

  const content = (
    <div className="w-full text-body-sm-regular">
      <div
        ref={issuePeekOverviewRef}
        className={peekOverviewClassName}
        style={{
          width: !embedIssue && peekMode === "side-peek" ? `${sidePeekWidth}px` : undefined,
          boxShadow:
            "0px 4px 8px 0px rgba(0, 0, 0, 0.12), 0px 6px 12px 0px rgba(16, 24, 40, 0.12), 0px 1px 16px 0px rgba(16, 24, 40, 0.12)",
        }}
      >
        {!embedIssue && peekMode === "side-peek" && (
          <div
            className="absolute top-0 left-0 z-[26] h-full w-4 -translate-x-1/2 cursor-ew-resize rounded-l-[28px] bg-transparent"
            onMouseDown={startPeekResizing}
            role="separator"
            aria-label="Resize external contour panel"
          />
        )}
        <ExternalContoursIssueActionsHeader
          workspaceSlug={workspaceSlug}
          sourceProjectId={projectId}
          contourRequest={contourRequest}
          hasDirectTargetAccess={hasDirectTargetAccess}
          isSubmitting={isSubmitting}
          removeRoutePeekId={removeRoutePeekId}
          peekMode={peekMode}
          setPeekMode={setPeekMode}
          embedIssue={embedIssue}
        />
        <div className="vertical-scrollbar relative scrollbar-md h-full w-full overflow-hidden overflow-y-auto">
          {["side-peek", "modal"].includes(peekMode) ? (
            <div className="relative flex flex-col gap-4 px-6 pt-3 pb-5">{children}</div>
          ) : (
            <div className="relative h-full w-full overflow-auto px-5 pt-3 pb-4">{children}</div>
          )}
        </div>
      </div>
    </div>
  );

  return <>{!embedIssue && portalContainer ? createPortal(content, portalContainer) : content}</>;
});
