import { useRef, useState, type DragEvent } from "react";
import { FileText, MessageSquare, Send, Upload } from "lucide-react";
import { Button, DynText, Panel, Tabs, TextArea } from "../../ui/primitives";
import { toast } from "../../ui/feedback";
import { t } from "../../i18n";
import { formatBytes } from "../../utils/format";
import s from "./Composer.module.css";

export type ComposerMode = "file" | "message";

export interface ComposerProps
{
    targetDevice: string | null;
    selectedFile: File | null;
    onFileChange: (f: File | null) => void;
    onSendFile: () => Promise<void> | void;
    onSendMessage: (text: string) => Promise<void> | void;
    /** 默认 'file'。 */
    initialMode?: ComposerMode;
}

export function Composer(props: ComposerProps)
{
    const {
        targetDevice, selectedFile,
        onFileChange, onSendFile, onSendMessage,
        initialMode = "file",
    } = props;

    const [ mode, setMode ] = useState<ComposerMode>(initialMode);
    const [ msgText, setMsgText ] = useState("");
    const fileInput = useRef<HTMLInputElement>(null);

    // 目标缺失时用 muted 提示而非 error 红 —— 提示职责与发送按钮的 disabled
    // 状态重合时不应双倍渲染告警。允许预输入文件/消息,等用户选完设备再点发送。
    // 设备名 span 的内容会随切换就地更新，名字含 CJK 时同样会被 shim 拆段累积；key=名字
    // 让它整体重挂。「发送到 」是常量文本节点、React 从不改写，无需处理。
    const targetLabel = targetDevice
        ? <>发送到 <span className={s.targetName} key={targetDevice}>{targetDevice}</span></>
        : <span className={s.targetMuted}>{t("home.cta.selectDevice")}</span>;

    const canSendFile = !!targetDevice && !!selectedFile;
    const canSendMsg  = !!targetDevice && msgText.trim().length > 0;

    // 「发送到 X」整串是单个文本节点，切换目标设备时 React 原地改写，聚珍 shim 拆出的旧
    // 碎片会残留累积（多出「到」）。DynText 用 key=文本让其整体重挂、保留排版又消累积。
    const sendLabel = targetDevice
        ? <DynText>{t("home.cta.sendTo", { name: targetDevice })}</DynText>
        : "发送";

    const handleSubmitFile = async () =>
    {
        if (!canSendFile) { return; }
        await onSendFile();
    };

    const handleSubmitMsg = async () =>
    {
        if (!targetDevice) { toast.warn(t("home.cta.selectDevice")); return; }
        if (!msgText.trim()) { return; }
        try
        {
            await onSendMessage(msgText);
            setMsgText("");
        }
        catch (e)
        {
            toast.error("消息发送失败", e instanceof Error ? e.message : String(e));
        }
    };

    return (
        <Panel
            variant="primary"
            padding="default"
            title={t("home.tabs.file") + " · " + t("home.tabs.message")}
            actions={
                <Tabs<ComposerMode>
                    items={[
                        { value: "file",    label: <span style={{ display: "inline-flex", alignItems: "center", gap: 4 }}><Upload size={13} />{t("home.tabs.file")}</span> },
                        { value: "message", label: <span style={{ display: "inline-flex", alignItems: "center", gap: 4 }}><MessageSquare size={13} />{t("home.tabs.message")}</span> },
                    ]}
                    value={mode}
                    onChange={setMode}
                    aria-label="compose mode"
                />
            }
        >
            <div className={s.root}>
                {/* targetLabel 必须包在单个 span 里,防聚珍（Juzhen）shim 拆段后
                    flex gap 在 CJK ↔ Latin 文本中间叠加 ——
                    同 Button.tsx 的 label span。 */}
                <div className={s.targetLine}><span>{targetLabel}</span></div>

                {mode === "file" ? (
                    <FilePane
                        selectedFile={selectedFile}
                        onFileChange={onFileChange}
                        fileInputRef={fileInput}
                    />
                ) : (
                    <TextArea
                        placeholder={targetDevice
                            ? t("home.message.placeholder", { name: targetDevice })
                            : t("home.message.placeholderEmpty")}
                        value={msgText}
                        onChange={(e) => setMsgText(e.currentTarget.value)}
                        rows={3}
                        hint={t("home.message.hint")}
                        onKeyDown={(e) =>
                        {
                            if (e.key === "Enter" && !e.shiftKey)
                            {
                                e.preventDefault();
                                void handleSubmitMsg();
                            }
                        }}
                    />
                )}

                {mode === "file" ? (
                    <Button
                        variant="primary"
                        size="md"
                        block
                        leftIcon={<Send size={14} />}
                        disabled={!canSendFile}
                        onClick={handleSubmitFile}
                    >
                        {sendLabel}
                    </Button>
                ) : (
                    <Button
                        variant="primary"
                        size="md"
                        block
                        leftIcon={<Send size={14} />}
                        disabled={!canSendMsg}
                        onClick={handleSubmitMsg}
                    >
                        {sendLabel}
                    </Button>
                )}
            </div>
        </Panel>
    );
}

interface FilePaneProps
{
    selectedFile: File | null;
    onFileChange: (f: File | null) => void;
    fileInputRef: React.RefObject<HTMLInputElement>;
}

function FilePane(props: FilePaneProps)
{
    const { selectedFile, onFileChange, fileInputRef } = props;
    const [ dragOver, setDragOver ] = useState(false);

    const onDragOver = (e: DragEvent<HTMLDivElement>) =>
    {
        if (!Array.from(e.dataTransfer.types).includes("Files")) { return; }
        e.preventDefault();
        e.dataTransfer.dropEffect = "copy";
        setDragOver(true);
    };

    const onDrop = (e: DragEvent<HTMLDivElement>) =>
    {
        e.preventDefault();
        setDragOver(false);
        const f = e.dataTransfer.files[0];
        if (f) { onFileChange(f); }
    };

    const cls = [
        s.dropzone,
        dragOver ? s.dropzoneActive : "",
        selectedFile ? s.dropzoneHasFile : "",
    ].filter(Boolean).join(" ");

    return (
        <>
            <div
                className={cls}
                onClick={() => fileInputRef.current?.click()}
                onDragOver={onDragOver}
                onDragLeave={() => setDragOver(false)}
                onDrop={onDrop}
                role="button"
                tabIndex={0}
                onKeyDown={(e) =>
                {
                    if (e.key === "Enter" || e.key === " ") {
                        e.preventDefault();
                        fileInputRef.current?.click();
                    }
                }}
            >
                {selectedFile ? (
                    <>
                        <div className={s.fileLine}>
                            <FileText size={16} />
                            <span>{selectedFile.name}</span>
                        </div>
                        <div className={s.fileMeta}>{formatBytes(selectedFile.size)}</div>
                        <button
                            type="button"
                            className={s.removeBtn}
                            onClick={(e) => { e.stopPropagation(); onFileChange(null); }}
                        >
                            移除
                        </button>
                    </>
                ) : (
                    <>
                        <Upload size={20} />
                        <span>{t("home.file.dropzone")}</span>
                    </>
                )}
            </div>
            <input
                ref={fileInputRef}
                type="file"
                style={{ display: "none" }}
                onChange={(e) =>
                {
                    const f = e.currentTarget.files?.[0];
                    if (f) { onFileChange(f); }
                    e.currentTarget.value = "";
                }}
            />
        </>
    );
}
