'use client';

import {
  type ChangeEvent,
  type ClipboardEvent,
  type KeyboardEvent,
  type RefObject,
  useCallback,
  useEffect,
  useRef,
  useState,
} from 'react';

import type { ChatAttachment } from '../types';
import { LIMITS } from '../config';

export interface UseChatComposerOptions {
  onSubmit: (content: string, attachments: ChatAttachment[]) => void | Promise<void>;
  initialValue?: string;
  maxLength?: number;
  maxAttachments?: number;
  disabled?: boolean;
  /** 'enter' = Enter sends, Shift+Enter newline. 'cmd+enter' = Enter inserts newline, Cmd/Ctrl+Enter sends. */
  submitOn?: 'enter' | 'cmd+enter';
  history?: { enabled?: boolean; size?: number };
  onPasteFiles?: (files: File[]) => void;
}

export interface UseChatComposerReturn {
  value: string;
  setValue: (next: string) => void;
  attachments: ChatAttachment[];
  addAttachment: (a: ChatAttachment) => void;
  removeAttachment: (id: string) => void;
  isSubmitting: boolean;
  canSubmit: boolean;
  submit: () => Promise<void>;
  reset: () => void;
  focus: () => void;
  textareaRef: RefObject<HTMLTextAreaElement | null>;
  textareaProps: {
    ref: RefObject<HTMLTextAreaElement | null>;
    value: string;
    disabled: boolean;
    onChange: (e: ChangeEvent<HTMLTextAreaElement>) => void;
    onKeyDown: (e: KeyboardEvent<HTMLTextAreaElement>) => void;
    onPaste: (e: ClipboardEvent<HTMLTextAreaElement>) => void;
  };
  recallPrevious: () => void;
  recallNext: () => void;
}

const MAX_TEXTAREA_HEIGHT = 240;

export function useChatComposer(options: UseChatComposerOptions): UseChatComposerReturn {
  const {
    onSubmit,
    initialValue = '',
    maxLength = LIMITS.messageMaxLength,
    maxAttachments = LIMITS.attachmentsMax,
    disabled = false,
    submitOn = 'enter',
    history = { enabled: true, size: LIMITS.composerHistorySize },
    onPasteFiles,
  } = options;

  const [value, setValueState] = useState(initialValue);
  const [attachments, setAttachments] = useState<ChatAttachment[]>([]);
  const [isSubmitting, setIsSubmitting] = useState(false);
  const textareaRef = useRef<HTMLTextAreaElement | null>(null);

  const historyRef = useRef<{ items: string[]; index: number }>({ items: [], index: -1 });

  const setValue = useCallback(
    (next: string) => {
      setValueState(next.length > maxLength ? next.slice(0, maxLength) : next);
    },
    [maxLength],
  );

  // Autosize textarea on value change.
  useEffect(() => {
    const el = textareaRef.current;
    if (!el) return;
    el.style.height = 'auto';
    el.style.height = `${Math.min(el.scrollHeight, MAX_TEXTAREA_HEIGHT)}px`;
  }, [value]);

  const reset = useCallback(() => {
    setValueState('');
    setAttachments([]);
    historyRef.current.index = -1;
  }, []);

  const focus = useCallback(() => {
    requestAnimationFrame(() => textareaRef.current?.focus());
  }, []);

  const submit = useCallback(async () => {
    const trimmed = value.trim();
    if ((!trimmed && attachments.length === 0) || isSubmitting || disabled) return;
    setIsSubmitting(true);
    try {
      if (history.enabled !== false && trimmed) {
        const buf = historyRef.current.items;
        if (buf[buf.length - 1] !== trimmed) {
          buf.push(trimmed);
          if (buf.length > (history.size ?? LIMITS.composerHistorySize)) buf.shift();
        }
        historyRef.current.index = -1;
      }
      const snapshot = [...attachments];
      const text = value;
      reset();
      await onSubmit(text, snapshot);
    } finally {
      setIsSubmitting(false);
    }
  }, [value, attachments, isSubmitting, disabled, history, onSubmit, reset]);

  const addAttachment = useCallback(
    (a: ChatAttachment) => {
      setAttachments((prev) => {
        if (prev.some((p) => p.id === a.id)) {
          return prev.map((p) => (p.id === a.id ? a : p));
        }
        if (prev.length >= maxAttachments) return prev;
        return [...prev, a];
      });
    },
    [maxAttachments],
  );

  const removeAttachment = useCallback((id: string) => {
    setAttachments((prev) => prev.filter((a) => a.id !== id));
  }, []);

  const recallPrevious = useCallback(() => {
    const { items } = historyRef.current;
    if (!items.length) return;
    const next = historyRef.current.index < 0 ? items.length - 1 : Math.max(0, historyRef.current.index - 1);
    historyRef.current.index = next;
    setValueState(items[next]);
  }, []);

  const recallNext = useCallback(() => {
    const { items } = historyRef.current;
    if (!items.length || historyRef.current.index < 0) return;
    const next = historyRef.current.index + 1;
    if (next >= items.length) {
      historyRef.current.index = -1;
      setValueState('');
      return;
    }
    historyRef.current.index = next;
    setValueState(items[next]);
  }, []);

  const onChange = useCallback(
    (e: ChangeEvent<HTMLTextAreaElement>) => {
      setValue(e.target.value);
    },
    [setValue],
  );

  const onKeyDown = useCallback(
    (e: KeyboardEvent<HTMLTextAreaElement>) => {
      if (e.key === 'Enter') {
        const isCmd = e.metaKey || e.ctrlKey;
        const shouldSend = submitOn === 'cmd+enter' ? isCmd : !e.shiftKey;
        if (shouldSend) {
          e.preventDefault();
          void submit();
        }
        return;
      }
      if (history.enabled !== false && value === '' && attachments.length === 0) {
        if (e.key === 'ArrowUp') {
          e.preventDefault();
          recallPrevious();
        } else if (e.key === 'ArrowDown' && historyRef.current.index >= 0) {
          e.preventDefault();
          recallNext();
        }
      }
    },
    [submitOn, submit, history, value, attachments.length, recallPrevious, recallNext],
  );

  const onPaste = useCallback(
    (e: ClipboardEvent<HTMLTextAreaElement>) => {
      const files = Array.from(e.clipboardData?.files ?? []);
      if (files.length && onPasteFiles) {
        e.preventDefault();
        onPasteFiles(files);
      }
    },
    [onPasteFiles],
  );

  const canSubmit =
    !disabled && !isSubmitting && (value.trim().length > 0 || attachments.length > 0);

  return {
    value,
    setValue,
    attachments,
    addAttachment,
    removeAttachment,
    isSubmitting,
    canSubmit,
    submit,
    reset,
    focus,
    textareaRef,
    textareaProps: {
      ref: textareaRef,
      value,
      disabled,
      onChange,
      onKeyDown,
      onPaste,
    },
    recallPrevious,
    recallNext,
  };
}
