import { useEffect, useMemo, useRef, useState } from "react";
import type {
  CSSProperties,
  PointerEvent as ReactPointerEvent,
  RefObject
} from "react";
import {
  clampComposerTextareaHeight,
  getComposerTextareaBounds
} from "../../lib/chat-utils";
import {
  COMPOSER_TEXTAREA_DEFAULT_MIN_HEIGHT,
  COMPOSER_TEXTAREA_DEFAULT_RATIO
} from "../../lib/constants";

interface UseComposerResizeOptions {
  isConversationView: boolean;
  workspaceRef: RefObject<HTMLDivElement | null>;
}

export function useComposerResize({ isConversationView, workspaceRef }: UseComposerResizeOptions) {
  const [isComposerResizeActive, setIsComposerResizeActive] = useState(false);
  const [composerTextareaRatio, setComposerTextareaRatio] = useState(COMPOSER_TEXTAREA_DEFAULT_RATIO);
  const [composerTextareaHeight, setComposerTextareaHeight] = useState(COMPOSER_TEXTAREA_DEFAULT_MIN_HEIGHT);
  const [composerWorkspaceHeight, setComposerWorkspaceHeight] = useState(0);
  const composerResizeDragRef = useRef<{ startY: number; startHeight: number; workspaceHeight: number } | null>(null);
  const hasComposerResizePreferenceRef = useRef(false);
  const composerTextareaBounds = useMemo(() => getComposerTextareaBounds(composerWorkspaceHeight), [composerWorkspaceHeight]);

  useEffect(() => {
    if (!isConversationView) {
      return;
    }

    const workspaceElement = workspaceRef.current;
    if (!workspaceElement) {
      return;
    }

    const updateComposerHeight = (workspaceHeight: number) => {
      const safeWorkspaceHeight = Number.isFinite(workspaceHeight) && workspaceHeight > 0 ? workspaceHeight : 0;
      setComposerWorkspaceHeight((currentHeight) => Math.abs(currentHeight - safeWorkspaceHeight) < 0.5 ? currentHeight : safeWorkspaceHeight);
      const bounds = getComposerTextareaBounds(safeWorkspaceHeight);
      const nextHeight = hasComposerResizePreferenceRef.current
        ? clampComposerTextareaHeight(safeWorkspaceHeight * composerTextareaRatio, safeWorkspaceHeight)
        : bounds.min;
      setComposerTextareaHeight((currentHeight) => Math.abs(currentHeight - nextHeight) < 0.5 ? currentHeight : nextHeight);
    };

    updateComposerHeight(workspaceElement.getBoundingClientRect().height);

    if (!("ResizeObserver" in window)) {
      return;
    }

    const observer = new ResizeObserver((entries) => {
      updateComposerHeight(entries[0]?.contentRect.height ?? workspaceElement.getBoundingClientRect().height);
    });
    observer.observe(workspaceElement);

    return () => observer.disconnect();
  }, [composerTextareaRatio, isConversationView, workspaceRef]);

  function handleComposerResizePointerDown(event: ReactPointerEvent<HTMLDivElement>) {
    if (event.button !== 0) {
      return;
    }

    const workspaceHeight = workspaceRef.current?.getBoundingClientRect().height ?? composerWorkspaceHeight;
    setComposerWorkspaceHeight((currentHeight) => Math.abs(currentHeight - workspaceHeight) < 0.5 ? currentHeight : workspaceHeight);
    composerResizeDragRef.current = {
      startY: event.clientY,
      startHeight: composerTextareaHeight,
      workspaceHeight
    };
    event.currentTarget.setPointerCapture(event.pointerId);
    setIsComposerResizeActive(true);
    event.preventDefault();
  }

  function handleComposerResizePointerMove(event: ReactPointerEvent<HTMLDivElement>) {
    const resizeState = composerResizeDragRef.current;
    if (!resizeState) {
      return;
    }

    const workspaceHeight = workspaceRef.current?.getBoundingClientRect().height || resizeState.workspaceHeight;
    const nextHeight = clampComposerTextareaHeight(resizeState.startHeight + resizeState.startY - event.clientY, workspaceHeight);
    setComposerWorkspaceHeight((currentHeight) => Math.abs(currentHeight - workspaceHeight) < 0.5 ? currentHeight : workspaceHeight);
    setComposerTextareaHeight(nextHeight);
    setComposerTextareaRatio(nextHeight / Math.max(workspaceHeight, 1));
    hasComposerResizePreferenceRef.current = true;
    event.preventDefault();
  }

  function handleComposerResizePointerEnd(event: ReactPointerEvent<HTMLDivElement>) {
    if (!composerResizeDragRef.current) {
      return;
    }

    composerResizeDragRef.current = null;
    if (event.currentTarget.hasPointerCapture(event.pointerId)) {
      event.currentTarget.releasePointerCapture(event.pointerId);
    }
    setIsComposerResizeActive(false);
    event.preventDefault();
  }

  const composerShellStyle = {
    "--composer-textarea-height": `${Math.round(composerTextareaHeight)}px`,
    "--composer-textarea-min-height": `${Math.round(composerTextareaBounds.min)}px`,
    "--composer-textarea-max-height": `${Math.round(composerTextareaBounds.max)}px`
  } as CSSProperties;

  return {
    isComposerResizeActive,
    composerShellStyle,
    handleComposerResizePointerDown,
    handleComposerResizePointerMove,
    handleComposerResizePointerEnd
  };
}
