import type { Locale } from "../i18n";

// Auth shape — see FRONTEND_DESIGN.md §6.
// access_token lives in sessionStorage so a tab refresh keeps the user logged in
// (PROJECT_BRIEF.md §2). The refresh_token never touches JS at all: in the
// browser it lives server-side behind an HttpOnly session cookie (see
// features/auth/auth.ts), on desktop inside the Go process (OS keyring).
export interface User
{
    id: string;
    name: string;
    /** Avatar URL from OIDC `picture` / Casdoor `avatar` claim. 空 / 加载失败时
        UI 回退到字母方块。 */
    avatar?: string;
}

export interface DeviceInfo
{
    name: string;
    type: string;
    online: boolean;
    lastSeen: number;
}

export type AuthMode = "dev" | "prod";

// 本会话的权限级别（来自 /api/me 的 scope）：full=完整登录、guest=受限访客。
// 受限访客不能管理账号 / 授权设备——前端据此隐藏相关入口（后端亦 403 兜底）。
export type SessionScope = "full" | "guest";

export type ThemeMode = "light" | "dark" | "system";

// 客户端侧细颗粒度阶段，与服务端的 state（PENDING/ACCEPTED/...）正交；
// 用来把"等待中/传输中"展开成具体正在做什么，配合 lastProgressAt 区分卡住。
export type TransferPhase =
    | "initializing"        // 刚 /initiate / 收到 transfer:incoming，未起 WebRTC
    | "waiting_accept"      // sender 等 /accept，receiver 等自己 /accept 回执
    | "ice_gathering"       // RTCPeerConnection 正在收集候选
    | "ice_checking"        // 候选已交换，连通性检查中
    | "ice_connected"       // ICE 通过，DC 即将打开
    | "dc_open"             // DataChannel 打开但还没开始传字节
    | "transferring"        // 字节正在流动
    | "completing"          // sender 已 send "done" / receiver 收到 "done"，等终态
    | "fallback_pending"    // 30s ICE 超时，已 POST /fallback，等 RELAY_ACTIVE 信号
    | "relay_uploading"     // 走 Relay 路径，sender 上传 chunk
    | "relay_downloading";  // 走 Relay 路径，receiver 流式 GET

// ICE 候选分类，用来回答"为什么 P2P 没建好"：
// host = 本机真实地址；mdns = 浏览器隐私混淆的 .local 主机名（同内网必须能解析）；
// srflx = STUN 反射的公网地址；prflx = peer-reflexive；relay = 通过 TURN 中转。
export interface CandidateBreakdown
{
    host:  number;
    mdns:  number;
    srflx: number;
    prflx: number;
    relay: number;
}

export interface IceStats
{
    gathering:    RTCIceGatheringState;
    connection:   RTCIceConnectionState;
    candidates:   { local: CandidateBreakdown; remote: CandidateBreakdown };
    selectedPair?: { local: string; remote: string };  // 形如 "host/udp" "relay/tcp"
    /** DataChannel 即时状态：诊断 sender 卡在 bufferedamountlow 用 */
    dataChannel?: {
        readyState: RTCDataChannelState;
        bufferedAmount: number;
    };
}

export interface TransferRecord
{
    sessionId: string;
    direction: "outgoing" | "incoming";
    fileName: string;
    fileSize: number;
    state: string;
    /**
     * "p2p" | "relay" | undefined.
     * Server emits this on the P2P_ACTIVE / RELAY_ACTIVE transition; the
     * client carries it forward into terminal states for history display.
     */
    mode?: string;
    peerName: string;
    startedAt: number;

    // ---- 客户端实时遥测 ------------------------------------------------------
    phase?: TransferPhase;
    /** 本端已传字节：outgoing 是 sender 已 send，incoming 是 receiver 已收 */
    bytesTransferred?: number;
    /** 上一次 bytesTransferred 增长的时刻（ms epoch），UI 据此判 stalled */
    lastProgressAt?: number;
    /** 瞬时传输速度（字节/秒，EMA 平滑）。由 upsertTransfer 据相邻样本差分算得，
     *  UI 仅在字节流动且未卡死时展示，避免显示误导性的 0 / 陈旧速率 */
    bytesPerSec?: number;
    iceStats?: IceStats;
}

// In-memory only — cleared on tab close, or via UI clear.
export interface MessageRecord
{
    id: string;
    direction: "incoming" | "outgoing";
    peerName: string;
    text: string;
    sentAt: number;
}

export interface ClipboardState
{
    content: string;
    contentType: string;
    sourceDevice: string;
    updatedAt: number;
    // version 是服务端每用户单调递增的版本号；条件 GET 的 ETag 用它（而非墙钟
    // updated_at），故同秒两写也能正确判变更。
    version: number;
}

export interface AppState
{
    // ---- auth slice ----
    authMode: AuthMode;
    accessToken: string | null;
    user: User | null;
    // 本会话权限级别（/api/me 的 scope）。默认 "full"；登录成功 / 开机水合后据
    // /api/me 校正为 "guest" 时，UI 隐藏「扫码登录新设备」「移除设备」「登出他人」
    // 等账号管理入口，并展示「受限访客」标识。
    sessionScope: SessionScope;
    setAuth: (a: { accessToken: string; user: User }) => void;
    setSessionScope: (scope: SessionScope) => void;
    clearAuth: () => void;

    // ---- device slice ----
    selfDeviceName: string | null;
    setSelfDeviceName: (name: string | null) => void;

    // ---- hub slice ----
    sseConnected: boolean;
    sseReconnecting: boolean;   // several straight SSE failures; UI shows a "reconnecting" banner — the loop keeps retrying, never gives up
    devices: DeviceInfo[];
    setSseConnected: (v: boolean) => void;
    setSseReconnecting: (v: boolean) => void;
    setDevices: (d: DeviceInfo[]) => void;

    // ---- transfer slice ----
    activeTransfers: Record<string, TransferRecord>;
    history: TransferRecord[];
    upsertTransfer: (t: TransferRecord) => void;
    completeTransfer: (sessionId: string, finalState: string) => void;
    /** 从列表移除一条记录（删除已完成的历史项 / 兜底清掉残留 active 项）。 */
    removeTransfer: (sessionId: string) => void;

    // ---- messages slice ----
    messages: MessageRecord[];
    addMessage: (m: MessageRecord) => void;
    removeMessage: (id: string) => void;
    clearMessages: () => void;

    // ---- clipboard slice ----
    clipboard: ClipboardState | null;
    setClipboard: (c: ClipboardState | null) => void;

    // ---- ui slice ----
    selectedDevice: string | null;
    selectedFile: File | null;
    setSelectedDevice: (n: string | null) => void;
    setSelectedFile: (f: File | null) => void;

    // ---- theme slice ----
    // 'system' 时移除 data-theme 让 @media (prefers-color-scheme) 接管；
    // 'light' / 'dark' 时写死 attribute。持久化到 localStorage。
    theme: ThemeMode;
    setTheme: (t: ThemeMode) => void;

    // ---- locale slice ----
    locale: Locale;
    setLocale: (l: Locale) => void;

    // ---- push slice ----
    // Web Push 的响应式镜像（权威态在浏览器 pushManager）。仅浏览器 / PWA 有意义，
    // 桌面壳走原生通知不读这两项。
    pushPermission: NotificationPermission;
    pushSubscribed: boolean;
    setPushPermission: (p: NotificationPermission) => void;
    setPushSubscribed: (b: boolean) => void;
}
