import type { TransferRecord, ThemeMode, User, SessionScope } from "./types";

// DONE 是"全部数据已交付"的语义终态，把进行时遥测残留归一到这一事实，避免
// history 行还显示"传输中字节 / 待发送 X MB"等错觉。FAILED / CANCELLED 不归
// 一：保留断点位置便于诊断，phase 字段告诉用户"卡在哪个阶段失败"。
export function normalizeTerminal(cur: TransferRecord, finalState: string): TransferRecord
{
    const result: TransferRecord = { ...cur, state: finalState };
    if (finalState !== "DONE") { return result; }
    result.phase = undefined;
    result.bytesTransferred = cur.fileSize;
    if (cur.iceStats?.dataChannel)
    {
        result.iceStats = {
            ...cur.iceStats,
            dataChannel: { ...cur.iceStats.dataChannel, bufferedAmount: 0 },
        };
    }
    return result;
}

// ---- storage keys & readers ----

export const ACCESS_TOKEN_KEY = "cdrop.access_token";
// refresh_token now lives in JS too (sessionStorage): after the Auth Broker migration
// a QR-paired device holds the broker's access + refresh pair directly and refreshes
// via /api/auth/refresh. A global-SSO browser holds neither (the broker domain cookie
// carries it). Desktop keeps its refresh in the Go process, never injected.
export const REFRESH_TOKEN_KEY = "cdrop.refresh_token";
export const USER_KEY         = "cdrop.user";
export const SESSION_SCOPE_KEY = "cdrop.session_scope";
export const SELF_DEVICE_KEY  = "cdrop.self_device";
export const THEME_KEY        = "cdrop.theme";

// 桌面壳的跨重启会话恢复：Go 侧在启动时从持久化文件读出 session，注入到
// index.html 的 window.__CDROP_SESSION__，因为 wails:// 自定义 scheme 下 WKWebView
// 的 localStorage / sessionStorage 都不跨重启存活（custom-scheme origin 无持久化
// 存储）。注入的全局在 bundle 执行前就绪，store 初始化即可同步水合。浏览器无此
// 注入，回落到 sessionStorage（刷新存活、关标签即清；refresh_token 仅在内存）。
// 注入的 session 不含 refresh_token——refresh_token 是长寿命密钥，只在 Go 进程里，
// 绝不进入 WebView（凭据策略见 desktop/platform/session.go）。
interface InjectedSession
{
    access_token: string;
    // refresh_token 现随注入会话一并下发（iOS 引擎自刷需要它）：引擎用它经
    // /api/auth/refresh 续期，并在 broker 轮换后回报原生更新 Keychain。桌面注入仍不带
    // （桌面 refresh 在 Go 进程内）。
    refresh_token?: string;
    user: { id: string; name: string; avatar?: string };
}

interface InjectedBoot
{
    session?: InjectedSession | null;
    device_name?: string;
    api_base?: string;
    device_type?: string;
}

function injectedBoot(): InjectedBoot | null
{
    if (typeof window === "undefined") { return null; }
    return (window as unknown as { __CDROP_BOOT__?: InjectedBoot }).__CDROP_BOOT__ ?? null;
}

function injectedSession(): InjectedSession | null
{
    const s = injectedBoot()?.session;
    return s && typeof s.access_token === "string" && s.access_token ? s : null;
}

// readInjectedDeviceName 在桌面壳里返回启动注入的设备名，让重启后路由守卫不再跳
// /setup（设备名同样存在 Go 侧、随 session 一并注入）；浏览器无注入返回 null。
export function readInjectedDeviceName(): string | null
{
    const name = injectedBoot()?.device_name;
    return name && name.length > 0 ? name : null;
}

// readInjectedApiBase 返回 /api 请求要前缀的来源。Windows 桌面壳注入 loopback
// HTTP 代理地址（http://127.0.0.1:PORT），让 SSE 走 WebView2 正常网络栈而非会缓冲
// 的 custom scheme；macOS 与浏览器无此注入、返回 ""（相对 URL、同源）。
export function readInjectedApiBase(): string
{
    const base = injectedBoot()?.api_base;
    return base && base.length > 0 ? base : "";
}

// readInjectedDeviceType 返回桌面壳注入的客户端类型（macos / windows / linux），
// 前端经 X-Device-Type 透传给后端，使设备列表不再把桌面端都标成 browser；浏览器
// 无注入返回 "browser"。
export function readInjectedDeviceType(): string
{
    const t = injectedBoot()?.device_type;
    return t && t.length > 0 ? t : "browser";
}

export function readSessionAccess(): string | null
{
    const inj = injectedSession();
    if (inj) { return inj.access_token; }
    if (typeof window === "undefined") { return null; }
    return window.sessionStorage.getItem(ACCESS_TOKEN_KEY);
}

// readSessionRefresh restores the broker refresh token across a same-tab reload.
// Desktop injection never carries it (refresh lives in the Go process); a global-SSO
// browser has none. Null when absent.
export function readSessionRefresh(): string | null
{
    const inj = injectedSession();
    if (inj?.refresh_token) { return inj.refresh_token; }
    if (typeof window === "undefined") { return null; }
    return window.sessionStorage.getItem(REFRESH_TOKEN_KEY);
}

// user.id / user.name 不是机密（公开显示在 UI、JWT 里可解码），随 access_token
// 一并持久化，才能让刷新 / 重启后路由守卫不再误跳 /login。
export function readSessionUser(): User | null
{
    const inj = injectedSession();
    if (inj?.user && typeof inj.user.id === "string" && typeof inj.user.name === "string")
    {
        return { id: inj.user.id, name: inj.user.name, avatar: inj.user.avatar };
    }
    if (typeof window === "undefined") { return null; }
    const raw = window.sessionStorage.getItem(USER_KEY);
    if (!raw) { return null; }
    try
    {
        const parsed = JSON.parse(raw) as unknown;
        if (
            parsed
            && typeof parsed === "object"
            && typeof (parsed as User).id === "string"
            && typeof (parsed as User).name === "string"
        )
        {
            return parsed as User;
        }
        return null;
    }
    catch
    {
        return null;
    }
}

// 本会话权限级别随 access_token 一并持久化（sessionStorage，同 tab 刷新存活、
// 关标签即清）。缺失 / 非法回退 "full"——/api/me 会在登录 / 水合后校正它，回退到
// 完整态只会多展示入口（后端仍 403），不会把受限态误升级。
export function readSessionScope(): SessionScope
{
    if (typeof window === "undefined") { return "full"; }
    const raw = window.sessionStorage.getItem(SESSION_SCOPE_KEY);
    return raw === "guest" ? "guest" : "full";
}

export function readSelfDevice(): string | null
{
    if (typeof window === "undefined") { return null; }
    return window.localStorage.getItem(SELF_DEVICE_KEY);
}

export function readTheme(): ThemeMode
{
    if (typeof window === "undefined") { return "system"; }
    const raw = window.localStorage.getItem(THEME_KEY);
    if (raw === "light" || raw === "dark" || raw === "system") { return raw; }
    return "system";
}
