/*
 * Runtime Web – Unified Serverless Framework for Full-Stack TypeScript Applications
 * Documentation: https://runtimeweb.com/docs/getting-started
 *
 * @template: ai-chat
 */

/**
 * InputComposer Component
 *
 * Enhanced message input area with auto-resize textarea, keyboard shortcuts,
 * focus states, and loading indicator. Provides a refined input experience
 * with micro-animations and accessibility support.
 *
 * @requirements 4.1, 4.2, 4.3, 4.4, 4.6, 4.7, 4.8
 */

import * as React from 'react';
import { useState, useCallback, useRef, useEffect, KeyboardEvent, ChangeEvent } from 'react';

/**
 * Props for the InputComposer component.
 */
export interface InputComposerProps {
    /** Callback invoked when user sends a message */
    onSend: (message: string) => void;
    /** Whether input is disabled (e.g., during request) */
    disabled: boolean;
    /** Placeholder text for the textarea */
    placeholder?: string;
}

/**
 * InputComposer provides a refined message input experience with
 * auto-resize, keyboard shortcuts, and micro-animations.
 *
 * Features:
 * - Auto-resize textarea (up to max height)
 * - Smooth focus ring animation
 * - Send button with hover, active, disabled states
 * - Loading spinner when disabled
 * - Keyboard shortcuts (Enter to send, Shift+Enter for newline)
 * - Visual keyboard shortcut hints
 * - Accessible with proper ARIA labels
 */
export const InputComposer: React.FC<InputComposerProps> = ({
    onSend,
    disabled,
    placeholder = 'Message AI...',
}) => {
    const [input, setInput] = useState('');
    const [isFocused, setIsFocused] = useState(false);
    const textareaRef = useRef<HTMLTextAreaElement>(null);

    /**
     * Auto-resize textarea based on content.
     * Respects max-height constraint from CSS (--input-max-height).
     */
    useEffect(() => {
        const textarea = textareaRef.current;
        if (textarea) {
            textarea.style.height = 'auto';
            const maxHeight = 200;
            textarea.style.height = `${Math.min(textarea.scrollHeight, maxHeight)}px`;
        }
    }, [input]);

    /**
     * Handle message submission.
     * Validates input is non-empty and not disabled.
     */
    const handleSubmit = useCallback(() => {
        const trimmed = input.trim();
        if (trimmed && !disabled) {
            onSend(trimmed);
            setInput('');
            if (textareaRef.current) {
                textareaRef.current.style.height = 'auto';
            }
        }
    }, [input, disabled, onSend]);

    /**
     * Handle keyboard events.
     * Enter submits, Shift+Enter inserts newline.
     */
    const handleKeyDown = useCallback(
        (e: KeyboardEvent<HTMLTextAreaElement>) => {
            if (e.key === 'Enter' && !e.shiftKey) {
                e.preventDefault();
                handleSubmit();
            }
        },
        [handleSubmit]
    );

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

    const handleFocus = useCallback(() => setIsFocused(true), []);
    const handleBlur = useCallback(() => setIsFocused(false), []);

    const canSend = input.trim().length > 0 && !disabled;

    const containerClassName = [
        'input-composer',
        isFocused ? 'input-composer--focused' : '',
        disabled ? 'input-composer--disabled' : '',
    ].filter(Boolean).join(' ');

    const sendButtonClassName = [
        'input-composer__send',
        canSend ? 'input-composer__send--active' : '',
        disabled ? 'input-composer__send--loading' : '',
    ].filter(Boolean).join(' ');

    return (
        <div className={containerClassName} data-testid="input-composer">
            <div className="input-composer__container">
                <textarea
                    ref={textareaRef}
                    className="input-composer__textarea"
                    value={input}
                    onChange={handleChange}
                    onKeyDown={handleKeyDown}
                    onFocus={handleFocus}
                    onBlur={handleBlur}
                    placeholder={placeholder}
                    disabled={disabled}
                    rows={1}
                    aria-label="Message input"
                    aria-describedby="input-composer-hint"
                    data-testid="input-composer-textarea"
                />
                <button
                    className={sendButtonClassName}
                    onClick={handleSubmit}
                    disabled={!canSend}
                    aria-label={disabled ? 'Sending message...' : 'Send message'}
                    type="button"
                    data-testid="input-composer-send"
                >
                    {disabled ? <LoadingSpinner /> : <SendIcon />}
                </button>
            </div>
            <div className="input-composer__hint" id="input-composer-hint">
                <kbd className="input-composer__kbd">Enter</kbd>
                <span className="input-composer__hint-text">to send</span>
                <span className="input-composer__hint-separator">·</span>
                <kbd className="input-composer__kbd">Shift + Enter</kbd>
                <span className="input-composer__hint-text">for new line</span>
            </div>
        </div>
    );
};

const SendIcon: React.FC = () => (
    <svg
        className="input-composer__icon"
        width="20"
        height="20"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        strokeWidth="2"
        strokeLinecap="round"
        strokeLinejoin="round"
        aria-hidden="true"
    >
        <path d="M22 2L11 13" />
        <path d="M22 2L15 22L11 13L2 9L22 2Z" />
    </svg>
);

const LoadingSpinner: React.FC = () => (
    <svg
        className="input-composer__spinner"
        width="20"
        height="20"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        strokeWidth="2"
        strokeLinecap="round"
        aria-hidden="true"
        data-testid="input-composer-spinner"
    >
        <circle cx="12" cy="12" r="10" strokeOpacity="0.25" />
        <path d="M12 2a10 10 0 0 1 10 10" />
    </svg>
);
