import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import React from "react";
import { Provider, createStore } from "jotai";
import { useEffect, useRef, useState } from "react";
import { chatInputErrorAtom, chatInputModeAtom, chatInputStatusAtom, chatInputTextAtom, chatInputTranscriptAtom, } from "../atoms/chatInputAtoms";
import { attachmentListAtom } from "../atoms/attachmentAtoms";
import { mergeChatInputTokens } from "../tokens/defaultTokens";
import { useAttachmentState } from "../hooks/useAttachmentState";
import { useChatInputState } from "../hooks/useChatInputState";
import { useVoiceInputController } from "../hooks/useVoiceInputController";
import { AttachmentPreview } from "./AttachmentPreview";
import { EmojiPicker } from "./EmojiPicker";
import { EmojiTrigger } from "./EmojiTrigger";
import { InputSurface } from "./InputSurface";
import { SendAction } from "./SendAction";
import { StatusHint } from "./StatusHint";
import { TextComposer } from "./TextComposer";
import { WaveformFeedback } from "./WaveformFeedback";
import { ImageOutlineIcon, MicOutlineIcon } from "./icons";
function DesktopInner(props) {
    const tokens = mergeChatInputTokens(props.tokens);
    const state = useChatInputState();
    const attachments = useAttachmentState();
    const [isEmojiOpen, setIsEmojiOpen] = useState(false);
    const [isUploadingImage, setIsUploadingImage] = useState(false);
    const textComposerRef = useRef(null);
    const emojiAnchorRef = useRef(null);
    const imageInputRef = useRef(null);
    const voice = useVoiceInputController({
        ...props.voice,
        onVoiceSend: async (blob) => {
            await props.voice?.onVoiceSend?.(blob);
            await props.onSend?.({
                text: state.text,
                attachments: state.attachments,
                transcript: state.transcript || undefined,
                audio: blob,
                mode: "voice",
            });
        },
    });
    useEffect(() => {
        if (props.value !== undefined) {
            state.setText(props.value);
        }
    }, [props.value]);
    const desktopStatusText = state.error ??
        (isUploadingImage
            ? "Uploading image..."
            :
                (voice.status === "recording"
                    ? "Recording... click mic again to transcribe"
                    : voice.status === "transcribing"
                        ? "Transcribing voice..."
                        : voice.status === "transcript-ready"
                            ? "Transcript inserted. Edit or send."
                            : undefined));
    const onSend = async () => {
        if (!props.onSend) {
            return;
        }
        state.setStatus("sending");
        await props.onSend({
            text: state.text,
            attachments: state.attachments,
            transcript: state.transcript || undefined,
        });
        state.setText("");
        state.setTranscript("");
        state.setAttachments([]);
        props.onChange?.("");
        state.setStatus("idle");
    };
    const handleImageFile = async (file) => {
        if (!props.image?.uploadImage) {
            attachments.addAttachment({
                name: file.name,
                file,
                previewUrl: URL.createObjectURL(file),
            });
            return;
        }
        setIsUploadingImage(true);
        state.setError(null);
        try {
            const uploaded = await props.image.uploadImage(file);
            attachments.addAttachment({
                name: uploaded.name ?? file.name,
                file,
                url: uploaded.url,
                previewUrl: uploaded.previewUrl ?? uploaded.url,
            });
        }
        catch (error) {
            state.setError(error instanceof Error ? error.message : "Failed to upload image");
            state.setStatus("error");
        }
        finally {
            setIsUploadingImage(false);
        }
    };
    const insertEmoji = (emoji) => {
        const textarea = textComposerRef.current;
        const start = textarea?.selectionStart ?? state.text.length;
        const end = textarea?.selectionEnd ?? state.text.length;
        const nextText = `${state.text.slice(0, start)}${emoji}${state.text.slice(end)}`;
        state.setText(nextText);
        state.setStatus(nextText.trim() ? "typing" : "idle");
        props.onChange?.(nextText);
        requestAnimationFrame(() => {
            textarea?.focus();
            const caret = start + emoji.length;
            textarea?.setSelectionRange(caret, caret);
        });
    };
    return (_jsx(InputSurface, { tokens: tokens, status: state.status, children: _jsxs("div", { className: "grid gap-3", style: { position: "relative" }, children: [_jsx("input", { ref: imageInputRef, type: "file", accept: props.image?.accept ?? "image/*", style: { display: "none" }, onChange: (event) => {
                        const file = event.target.files?.[0];
                        if (file) {
                            void handleImageFile(file);
                        }
                        event.currentTarget.value = "";
                    } }), _jsx(EmojiPicker, { open: isEmojiOpen, isMobile: false, anchorRef: emojiAnchorRef, onSelect: insertEmoji, onClose: () => setIsEmojiOpen(false) }), _jsx(TextComposer, { ref: textComposerRef, tokens: tokens, value: state.text, placeholder: "Message PMate", onChange: (event) => {
                        state.setText(event.target.value);
                        state.setStatus(event.target.value.trim() ? "typing" : "idle");
                        props.onChange?.(event.target.value);
                    } }), _jsx(AttachmentPreview, { attachments: attachments.attachments, tokens: tokens }), voice.status === "recording" ? (_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(WaveformFeedback, { levels: voice.waveformLevels, tokens: tokens, compact: true }), _jsxs("span", { style: { color: tokens.color.textSecondary, fontSize: 12 }, children: [Math.max(1, Math.round(voice.durationMs / 1000)), "s"] })] })) : null, _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(EmojiTrigger, { ref: emojiAnchorRef, style: { color: "#616161" }, onClick: () => setIsEmojiOpen((prev) => !prev) }), _jsx("button", { type: "button", onClick: () => imageInputRef.current?.click(), style: {
                                        display: "inline-flex",
                                        alignItems: "center",
                                        justifyContent: "center",
                                        width: 32,
                                        height: 32,
                                        border: 0,
                                        background: "transparent",
                                        color: "#616161",
                                        cursor: props.disabled || isUploadingImage ? "not-allowed" : "pointer",
                                        opacity: props.disabled || isUploadingImage ? 0.4 : 1,
                                    }, disabled: props.disabled || isUploadingImage, children: _jsx(ImageOutlineIcon, { size: 22 }) }), _jsx("button", { type: "button", onClick: () => {
                                        if (props.disabled || props.enableVoice === false) {
                                            return;
                                        }
                                        if (voice.status === "recording") {
                                            voice.stopRecording("transcribe");
                                            return;
                                        }
                                        voice.beginVoiceMode();
                                        voice.startRecording();
                                    }, style: {
                                        display: "inline-flex",
                                        alignItems: "center",
                                        justifyContent: "center",
                                        width: 32,
                                        height: 32,
                                        border: 0,
                                        background: "transparent",
                                        color: voice.status === "recording" || voice.status === "transcribing"
                                            ? tokens.color.iconActive
                                            : "#616161",
                                        cursor: props.disabled || props.enableVoice === false ? "not-allowed" : "pointer",
                                        opacity: props.disabled || props.enableVoice === false ? 0.4 : 1,
                                    }, "aria-label": voice.status === "recording"
                                        ? "停止录音并转文字"
                                        : "开始语音输入", children: _jsx(MicOutlineIcon, { size: 22 }) })] }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { style: { color: tokens.color.textSecondary, fontSize: 12 }, children: "Enter send / Shift+Enter newline" }), _jsx(SendAction, { tokens: tokens, disabled: props.disabled || (!state.text.trim() && state.attachments.length === 0), onClick: () => void onSend(), children: "Send" })] })] }), _jsx(StatusHint, { tokens: tokens, text: desktopStatusText, tone: state.error ? "error" : "secondary" })] }) }));
}
export function ChatInputDesktop(props) {
    const stateKey = JSON.stringify({
        initialState: props.initialState,
        defaultValue: props.defaultValue,
    });
    const storeRef = useRef(null);
    if (!storeRef.current || storeRef.current.key !== stateKey) {
        const store = createStore();
        store.set(chatInputModeAtom, props.initialState?.mode ?? "text");
        store.set(chatInputStatusAtom, props.initialState?.status ?? "idle");
        store.set(chatInputTextAtom, props.initialState?.text ?? props.defaultValue ?? "");
        store.set(chatInputTranscriptAtom, props.initialState?.transcript ?? "");
        store.set(chatInputErrorAtom, props.initialState?.error ?? null);
        store.set(attachmentListAtom, props.initialState?.attachments ?? []);
        storeRef.current = { key: stateKey, store };
    }
    return (_jsx(Provider, { store: storeRef.current.store, children: _jsx(DesktopInner, { ...props }) }));
}
