'use client';

import { useMemo } from 'react';
import { ArrowUp, Paperclip, Square } from 'lucide-react';

import type { UseChatComposerReturn } from '../hooks/useChatComposer';
import type { ComposerAction } from './types';

/** `order` values reserved for built-in actions so host extras land between. */
const ORDER = {
  attach: 100,
  hostStart: 200,
  hostEnd: 200,
  mic: 800,
  send: 900,
} as const;

export interface UseComposerActionsParams {
  composer: UseChatComposerReturn;
  isStreaming: boolean;
  isDisabled: boolean;
  /** Built-in attach action wiring. */
  showAttachmentButton?: boolean;
  onPickFiles?: () => void;
  attachLabel?: string;
  /** Host-supplied declarative clusters. */
  actionsStart?: ComposerAction[];
  actionsEnd?: ComposerAction[];
  /** Send / stop wiring. */
  onSend: () => void;
  onCancel?: () => void;
  sendLabel?: string;
  stopLabel?: string;
  /** Telegram-style mic↔send swap. When true (default), mic and send never
   *  show together — mic when the draft is empty, send once there is text. */
  micSendSwap?: boolean;
}

export interface ComposerActionClusters {
  actionsStart: ComposerAction[];
  actionsEnd: ComposerAction[];
}

/**
 * Merges built-in send/stop/attach descriptors with host-provided arrays,
 * applies `hideWhen` against live composer state, resolves the mic↔send
 * swap, and sorts each cluster by `order`.
 */
export function useComposerActions(params: UseComposerActionsParams): ComposerActionClusters {
  const {
    composer,
    isStreaming,
    isDisabled,
    showAttachmentButton,
    onPickFiles,
    attachLabel = 'Attach files',
    actionsStart,
    actionsEnd,
    onSend,
    onCancel,
    sendLabel = 'Send',
    stopLabel = 'Stop',
    micSendSwap = true,
  } = params;

  const hasText = composer.canSubmit;
  const canSubmit = composer.canSubmit;

  return useMemo(() => {
    const start: ComposerAction[] = [];
    const end: ComposerAction[] = [];

    if (showAttachmentButton) {
      start.push({
        id: 'attach',
        icon: <Paperclip aria-hidden />,
        label: attachLabel,
        onClick: () => onPickFiles?.(),
        disabled: isDisabled,
        variant: 'ghost',
        order: ORDER.attach,
      });
    }

    for (const a of actionsStart ?? []) {
      start.push({ order: ORDER.hostStart, ...a });
    }
    for (const a of actionsEnd ?? []) {
      end.push({ order: ORDER.hostEnd, ...a });
    }

    // Send / stop. While streaming → stop; otherwise → send. Both are
    // round, theme-inverting buttons (ChatGPT/Gemini style).
    if (isStreaming) {
      end.push({
        id: 'stop',
        icon: <Square aria-hidden />,
        label: stopLabel,
        onClick: () => onCancel?.(),
        variant: 'send',
        order: ORDER.send,
      });
    } else {
      end.push({
        id: 'send',
        icon: <ArrowUp aria-hidden />,
        label: sendLabel,
        onClick: onSend,
        disabled: !canSubmit,
        variant: 'send',
        order: ORDER.send,
      });
    }

    // Apply `hideWhen` against the live composer state.
    const visible = (a: ComposerAction): boolean => {
      switch (a.hideWhen) {
        case 'streaming':
          return !isStreaming;
        case 'empty':
          return hasText;
        case 'hasText':
          return !hasText;
        case 'disabled':
          return !isDisabled;
        default:
          return true;
      }
    };

    let filteredEnd = end.filter(visible);
    const filteredStart = start.filter(visible);

    // Mic↔send swap: when there is text and a mic action exists, drop the
    // mic so only send shows. The host marks its mic with `id: 'mic'`
    // (or `hideWhen: 'hasText'`); this is a safety net for the common id.
    if (micSendSwap && hasText) {
      filteredEnd = filteredEnd.filter((a) => a.id !== 'mic');
    }

    const byOrder = (a: ComposerAction, b: ComposerAction) =>
      (a.order ?? 0) - (b.order ?? 0);

    return {
      actionsStart: filteredStart.sort(byOrder),
      actionsEnd: filteredEnd.sort(byOrder),
    };
  }, [
    showAttachmentButton,
    attachLabel,
    onPickFiles,
    isDisabled,
    actionsStart,
    actionsEnd,
    isStreaming,
    stopLabel,
    onCancel,
    sendLabel,
    onSend,
    canSubmit,
    hasText,
    micSendSwap,
  ]);
}
