import Foundation

/// 主控端 HTTP 客户端：对接安全信令服务器的账号体系与自助接口。
///
///  - login(username,password) → accessToken + refreshToken（一次性，ses_ 前缀）；
///  - refresh(refreshToken) → 新 accessToken（服务端可能轮换 refreshToken）；
///  - verify() → 校验 accessToken 是否仍有效；
///  - bindings() → 本机可连接的被控端列表（仅已绑定设备）；
///  - turnCredentials() → TURN 短期凭证（服务端开启时返回 iceServers）。
struct ApiClient {

    /// 服务端 HTTP 基址（与信令同源）。部署时通过 Build Setting / Info.plist 注入。
    static var baseURL: String {
        // 优先读取 Info.plist 中的 APIBase，缺省回退到信号服务器同源 HTTPS。
        if let v = Bundle.main.object(forInfoDictionaryKey: "APIBase") as? String, !v.isEmpty {
            return v
        }
        return "https://www.ttstd.com"
    }

    /// 登录：成功返回 accessToken / refreshToken / expireAt。
    static func login(username: String, password: String) async throws -> [String: Any] {
        let body: [String: Any] = ["username": username, "password": password]
        return try await post("/api/auth/login", body: body)
    }

    /// 刷新令牌：body 需带 refreshToken；成功返回新的 accessToken（可能轮换 refreshToken）。
    static func refresh(refreshToken: String) async throws -> [String: Any] {
        let body: [String: Any] = ["refreshToken": refreshToken]
        return try await post("/api/auth/refresh", body: body)
    }

    /// 校验当前 accessToken 是否有效。
    static func verify(accessToken: String) async throws -> [String: Any] {
        return try await get("/api/client/verify", accessToken: accessToken)
    }

    /// 拉取本机可连接的被控端绑定列表（仅已绑定设备）。
    static func bindings(accessToken: String) async throws -> [String: Any] {
        return try await get("/api/client/bindings", accessToken: accessToken)
    }

    /// 拉取 TURN 短期凭证（服务端未开启时抛错，调用方忽略）。
    static func turnCredentials(accessToken: String) async throws -> [String: Any] {
        return try await get("/api/client/turn-credentials", accessToken: accessToken)
    }

    // MARK: - Private

    private static func post(_ path: String, body: [String: Any]) async throws -> [String: Any] {
        var req = URLRequest(url: URL(string: baseURL + path)!)
        req.httpMethod = "POST"
        req.setValue("application/json", forHTTPHeaderField: "Content-Type")
        req.httpBody = try JSONSerialization.data(withJSONObject: body)
        return try await perform(req)
    }

    private static func get(_ path: String, accessToken: String) async throws -> [String: Any] {
        var req = URLRequest(url: URL(string: baseURL + path)!)
        req.httpMethod = "GET"
        req.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
        return try await perform(req)
    }

    private static func perform(_ request: URLRequest) async throws -> [String: Any] {
        let (data, response) = try await URLSession.shared.data(for: request)
        guard let http = response as? HTTPURLResponse else {
            throw ApiError(message: "无效响应")
        }
        if http.statusCode == 401 {
            throw ApiError(code: "UNAUTHORIZED", message: "令牌失效", httpCode: 401)
        }
        guard (200..<300).contains(http.statusCode) else {
            let msg = (try? JSONSerialization.jsonObject(with: data) as? [String: Any])?["error"] as? String
                ?? "HTTP \(http.statusCode)"
            throw ApiError(message: msg)
        }
        return (try? JSONSerialization.jsonObject(with: data) as? [String: Any]) ?? [:]
    }
}

struct ApiError: Error {
    let code: String
    let message: String
    let httpCode: Int

    init(code: String = "ERROR", message: String, httpCode: Int = -1) {
        self.code = code
        self.message = message
        self.httpCode = httpCode
    }

    var localizedDescription: String { message }
}
