'use client';

import { type ReactNode, forwardRef } from 'react';
import { Paperclip, Send, Square } from 'lucide-react';

import { Button, Textarea } from '@djangocfg/ui-core/components';
import { cn } from '@djangocfg/ui-core/lib';

import { useChatContextOptional } from '../context';
import type { UseChatComposerReturn } from '../hooks/useChatComposer';
import { Attachments } from './Attachments';

export type ComposerSize = 'sm' | 'md' | 'lg';

export interface ComposerProps {
  composer: UseChatComposerReturn;
  placeholder?: string;
  disabled?: boolean;
  showAttachmentButton?: boolean;
  onPickFiles?: () => void;
  toolbarStart?: ReactNode;
  toolbarEnd?: ReactNode;
  attachmentTray?: ReactNode;
  className?: string;
  textareaClassName?: string;
  /** Visual size — controls textarea height + button slot size.
   *
   * - ``sm``  — 32px slot, dense compact composer (admin sidebars, etc).
   * - ``md``  — 36px slot, default. Same as the legacy fixed size.
   * - ``lg``  — 48px slot, generous textarea. Use when the chat is
   *   the page's primary surface (onboarding, support).
   */
  size?: ComposerSize;
  /** Show "Stop" button instead of "Send" while streaming. */
  isStreaming?: boolean;
  onCancel?: () => void;
}

const SIZE_CLASSES: Record<ComposerSize, {
  slot: string;
  button: string;
  iconButton: string;
  textarea: string;
  text: string;
  padding: string;
  containerPadding: string;
}> = {
  sm: {
    slot: '[&>:not(textarea)]:h-8',
    button: 'h-8 w-8',
    iconButton: 'size-3.5',
    textarea: 'min-h-8 max-h-48 px-3 py-1.5',
    text: 'text-sm',
    padding: 'gap-1.5',
    containerPadding: 'px-2 pt-1.5 pb-[max(0.375rem,env(safe-area-inset-bottom))]',
  },
  md: {
    slot: '[&>:not(textarea)]:h-9',
    button: 'h-9 w-9',
    iconButton: 'size-4',
    textarea: 'min-h-9 max-h-60 px-3.5 py-2',
    text: 'text-base sm:text-sm',
    padding: 'gap-1.5',
    containerPadding: 'px-2.5 pt-2 pb-[max(0.5rem,env(safe-area-inset-bottom))]',
  },
  lg: {
    slot: '[&>:not(textarea)]:h-12',
    button: 'h-12 w-12',
    iconButton: 'size-5',
    textarea: 'min-h-12 max-h-72 px-4 py-3',
    text: 'text-base',
    padding: 'gap-2',
    containerPadding: 'px-3.5 pt-3 pb-[max(0.875rem,env(safe-area-inset-bottom))]',
  },
};

export const Composer = forwardRef<HTMLDivElement, ComposerProps>(function Composer(
  {
    composer,
    placeholder = 'Type a message...',
    disabled,
    showAttachmentButton = false,
    onPickFiles,
    toolbarStart,
    toolbarEnd,
    attachmentTray,
    className,
    textareaClassName,
    size = 'md',
    isStreaming: isStreamingProp,
    onCancel: onCancelProp,
  },
  ref,
) {
  const ctx = useChatContextOptional();
  const isStreaming = isStreamingProp ?? ctx?.isStreaming ?? false;
  const onCancel = onCancelProp ?? ctx?.cancelStream;
  const isDisabled = disabled ?? isStreaming;
  const sz = SIZE_CLASSES[size];

  return (
    <div
      ref={ref}
      className={cn(
        'border-t border-border bg-background/95',
        sz.containerPadding,
        className,
      )}
    >
      {composer.attachments.length > 0 ? (
        <div className="mb-1.5">
          {attachmentTray ?? (
            <Attachments
              attachments={composer.attachments}
              onRemove={(a) => composer.removeAttachment(a.id)}
            />
          )}
        </div>
      ) : null}

      {/* Size-aware slot row. ``[&>:not(textarea)]:h-{N}`` enforces a
       *   consistent slot height so toolbar buttons line up with the
       *   textarea baseline. Toolbar slots that want to opt out can
       *   pass an explicit class like `!h-auto`. */}
      <div className={cn('flex items-end [&>:not(textarea)]:shrink-0', sz.padding, sz.slot)}>
        {showAttachmentButton ? (
          <Button
            type="button"
            variant="ghost"
            size="icon"
            onClick={onPickFiles}
            aria-label="Attach files"
            disabled={isDisabled}
            className={sz.button}
          >
            <Paperclip aria-hidden className={sz.iconButton} />
          </Button>
        ) : null}

        {toolbarStart}

        <Textarea
          {...composer.textareaProps}
          rows={1}
          placeholder={placeholder}
          aria-label={placeholder}
          aria-multiline="true"
          disabled={isDisabled}
          className={cn(
            'flex-1 resize-none rounded-2xl',
            sz.textarea,
            sz.text,
            textareaClassName,
          )}
        />

        {toolbarEnd}

        {isStreaming ? (
          <Button
            type="button"
            variant="secondary"
            size="icon"
            onClick={onCancel}
            aria-label="Stop"
            aria-keyshortcuts="Escape"
            className={sz.button}
          >
            <Square aria-hidden className={sz.iconButton} />
          </Button>
        ) : (
          <Button
            type="button"
            size="icon"
            onClick={() => void composer.submit()}
            disabled={!composer.canSubmit}
            aria-label="Send"
            aria-keyshortcuts="Enter"
            className={sz.button}
          >
            <Send aria-hidden className={sz.iconButton} />
          </Button>
        )}
      </div>
    </div>
  );
});
