import { useState } from "react";
import { ChevronDown } from "lucide-react";
import type { TransferPhase, TransferRecord } from "../../store";
import { useAppStore } from "../../store";
import { t, type TranslationKey } from "../../i18n";
import { formatBytes } from "../../utils/format";
import { DynText } from "../../ui/primitives";
import { cancelTransfer, skipWaitRelay } from "./transfer";
import { TransferDetails } from "./TransferDetails";
import s from "./TransferRow.module.css";

// 8 秒内字节没增长且当前 phase 是字节流动阶段 → 视为卡住。
const FLOW_PHASES: ReadonlySet<TransferPhase> = new Set([
    "transferring", "relay_uploading", "relay_downloading",
]);
const STALLED_THRESHOLD_MS = 8_000;

const STATE_KEYS: Record<string, TranslationKey> = {
    PENDING:      "transfer.state.PENDING",
    ACCEPTED:     "transfer.state.ACCEPTED",
    P2P_ACTIVE:   "transfer.state.P2P_ACTIVE",
    RELAY_ACTIVE: "transfer.state.RELAY_ACTIVE",
    DONE:         "transfer.state.DONE",
    FAILED:       "transfer.state.FAILED",
    CANCELLED:    "transfer.state.CANCELLED",
};

export interface TransferRowProps
{
    record: TransferRecord;
    active: boolean;
    now: number;
}

export function TransferRow(props: TransferRowProps)
{
    const { record: tr, active, now } = props;
    const [ detailOpen, setDetailOpen ] = useState(false);
    const removeTransfer = useAppStore((st) => st.removeTransfer);
    const arrow = tr.direction === "outgoing" ? "→" : "←";

    const sinceMs = tr.lastProgressAt ? now - tr.lastProgressAt : 0;
    const stalled = active
        && tr.state !== "DONE"
        && tr.phase !== undefined
        && FLOW_PHASES.has(tr.phase)
        && sinceMs >= STALLED_THRESHOLD_MS;

    const status = userFriendlyStatus(tr, stalled, sinceMs);
    const speed = speedText(tr, stalled);
    const pct = computeProgress(tr);
    const failed = tr.state === "FAILED";
    const done   = tr.state === "DONE";

    const barFillCls = [
        s.barFill,
        stalled ? s.barFillStalled : "",
        failed  ? s.barFillError   : "",
        done    ? s.barFillDone    : "",
    ].filter(Boolean).join(" ");

    // 左色条状态编码:active / stalled / failed / done 各对应一个语义色。
    // 优先级 failed > done > stalled > active,与 progress bar 颜色一致。
    const cancelled = tr.state === "CANCELLED";
    const rowStateCls
        = failed || cancelled ? s.rowFailed
        : done                ? s.rowDone
        : stalled             ? s.rowStalled
        : active              ? s.rowActive
        : "";

    // 终态记录可删除（从列表移除）；非终态记录可取消（驱动后端 /cancel）。
    const terminal = done || failed || cancelled;
    // 发送方仍在试 P2P（已接受 / P2P 中、尚未切中继）时，给一个「立即中继」入口，
    // 跳过 30s ICE 等待——只对 outgoing 有意义（驱动后端 /fallback）。
    const canRelayNow = tr.direction === "outgoing"
        && (tr.state === "ACCEPTED" || tr.state === "P2P_ACTIVE")
        && tr.phase !== "fallback_pending"
        && tr.phase !== "relay_uploading"
        && tr.phase !== "relay_downloading";

    return (
        <div className={[ s.row, done ? s.rowSunken : "", rowStateCls ].filter(Boolean).join(" ")}>
            <div className={s.head}>
                <span className={s.arrow}>{arrow}</span>
                <span className={s.fileName}>{tr.fileName}</span>
                <span className={s.peer}>{tr.peerName}</span>
            </div>

            <div className={s.barRow}>
                <div className={s.bar}>
                    <div className={barFillCls} style={{ width: `${pct}%` }} />
                </div>
                <span className={s.pct}>{Math.round(pct)}%</span>
            </div>

            <div className={s.meta}>
                {/* 状态文案含 CJK 且每秒 / 随 phase 就地更新；DynText 用 key 让其整体重挂，
                    避免聚珍 shim 拆出的碎片累积（见 DynText）。 */}
                <span className={s.metaItem}><DynText>{status}</DynText></span>
                {bytesText(tr) && (
                    <>
                        <span className={s.dot}>·</span>
                        <span className={s.metaItem}>{bytesText(tr)}</span>
                    </>
                )}
                {speed && (
                    <>
                        <span className={s.dot}>·</span>
                        {/* 速度含 CJK「/秒」且高频更新，同样过 DynText */}
                        <span className={s.metaItem}><DynText>{speed}</DynText></span>
                    </>
                )}
            </div>

            <div className={s.footer}>
                <div className={s.actions}>
                    {canRelayNow && (
                        <button
                            type="button"
                            className={s.actionBtn}
                            onClick={() => void skipWaitRelay(tr.sessionId)}
                        >
                            {t("transfer.action.relayNow")}
                        </button>
                    )}
                    {terminal ? (
                        <button
                            type="button"
                            className={`${s.actionBtn} ${s.actionDanger}`}
                            onClick={() => removeTransfer(tr.sessionId)}
                        >
                            {t("transfer.action.delete")}
                        </button>
                    ) : (
                        <button
                            type="button"
                            className={`${s.actionBtn} ${s.actionDanger}`}
                            onClick={() => void cancelTransfer(tr.sessionId)}
                        >
                            {t("transfer.action.cancel")}
                        </button>
                    )}
                </div>
                <button
                    type="button"
                    className={s.detailToggle}
                    onClick={() => setDetailOpen((v) => !v)}
                    aria-expanded={detailOpen}
                >
                    <ChevronDown
                        size={11}
                        style={{
                            transform: detailOpen ? "rotate(0deg)" : "rotate(-90deg)",
                            transition: "transform 120ms",
                        }}
                    />
                    {t("transfer.action.details")}
                </button>
            </div>

            {detailOpen && <TransferDetails record={tr} />}
        </div>
    );
}

function userFriendlyStatus(tr: TransferRecord, stalled: boolean, sinceMs: number): string
{
    if (tr.state === "DONE")      { return t("transfer.state.DONE"); }
    if (tr.state === "FAILED")    { return "连接失败"; }
    if (tr.state === "CANCELLED") { return t("transfer.state.CANCELLED"); }
    if (stalled) { return t("transfer.stalled", { seconds: Math.floor(sinceMs / 1000) }); }
    if (tr.phase)
    {
        const key = `transfer.phase.${tr.phase}` as TranslationKey;
        return t(key);
    }
    const k = STATE_KEYS[tr.state];
    return k ? t(k) : tr.state;
}

function bytesText(tr: TransferRecord): string
{
    if (!FLOW_PHASES.has(tr.phase ?? "initializing")) { return ""; }
    return t("transfer.bytesProgress", {
        sent:  formatBytes(tr.bytesTransferred ?? 0),
        total: formatBytes(tr.fileSize),
    });
}

// 瞬时速度文案。仅在字节流动阶段、未卡死、且有正有限速率时给出——卡死时既有「似乎
// 卡住了」状态已表达停滞，再显示一个陈旧的非零速度会误导。速率由 store 做 EMA 平滑。
function speedText(tr: TransferRecord, stalled: boolean): string
{
    if (stalled) { return ""; }
    if (!FLOW_PHASES.has(tr.phase ?? "initializing")) { return ""; }
    const rate = tr.bytesPerSec;
    if (!rate || !Number.isFinite(rate) || rate <= 0) { return ""; }
    return t("transfer.bytesRate", { rate: formatBytes(rate) });
}

function computeProgress(tr: TransferRecord): number
{
    if (tr.state === "DONE") { return 100; }
    if (tr.state === "FAILED" || tr.state === "CANCELLED")
    {
        // 失败/取消时若有进度则保留,无则给极小值占位
        if (typeof tr.bytesTransferred === "number" && tr.fileSize > 0)
        {
            return Math.min(100, (tr.bytesTransferred / tr.fileSize) * 100);
        }
        return 0;
    }
    if (typeof tr.bytesTransferred === "number" && tr.fileSize > 0)
    {
        return Math.min(100, Math.max(2, (tr.bytesTransferred / tr.fileSize) * 100));
    }
    switch (tr.state)
    {
        case "PENDING":      return 5;
        case "ACCEPTED":     return 15;
        case "P2P_ACTIVE":
        case "RELAY_ACTIVE": return 50;
        default:             return 0;
    }
}
