import Foundation

/// KBChatMQ Hub — HTTP client (Swift, URLSession). Chỉ URL Hub; secret truyền khi gọi.
public final class KbChatMqClient: @unchecked Sendable {
    private let apiBase: String
    private let session: URLSession

    public init(baseUrl: String, session: URLSession = .shared) {
        var s = baseUrl.trimmingCharacters(in: .whitespacesAndNewlines)
        while s.last == "/" { s.removeLast() }
        self.apiBase = s.hasSuffix("/api") ? s : "\(s)/api"
        self.session = session
    }

    public struct JsonResult: Sendable {
        public let ok: Bool
        public let status: Int
        public let data: [String: Any]
    }

    private func json(path: String, method: String, body: [String: Any]? = nil) async throws -> JsonResult {
        let p = path.hasPrefix("/") ? path : "/\(path)"
        guard let url = URL(string: apiBase + p) else {
            throw URLError(.badURL)
        }
        var req = URLRequest(url: url)
        req.httpMethod = method
        req.setValue("application/json", forHTTPHeaderField: "Accept")
        if let body = body {
            req.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
            req.httpBody = try JSONSerialization.data(withJSONObject: body)
        }
        let (data, resp) = try await session.data(for: req)
        let status = (resp as? HTTPURLResponse)?.statusCode ?? 0
        let obj: [String: Any]
        if let d = try? JSONSerialization.jsonObject(with: data) as? [String: Any] {
            obj = d
        } else {
            obj = ["ok": false, "error": "invalid_json"]
        }
        let okFlag = (200..<300).contains(status) && (obj["ok"] as? Bool != false)
        return JsonResult(ok: okFlag, status: status, data: obj)
    }

    public func loginWithPassword(userId: String, password: String) async throws -> JsonResult {
        try await json(path: "/auth/login", method: "POST", body: ["userId": userId, "password": password])
    }

    public func loginWithUserToken(userToken: String) async throws -> JsonResult {
        try await json(path: "/auth/login-token", method: "POST", body: ["userToken": userToken])
    }

    public func loginVisitor(websiteToken: String, visitorId: String? = nil) async throws -> JsonResult {
        var b: [String: Any] = ["websiteToken": websiteToken]
        if let v = visitorId { b["visitorId"] = v }
        return try await json(path: "/auth/login-visitor", method: "POST", body: b)
    }

    public func loginDevice(deviceToken: String, deviceId: String? = nil) async throws -> JsonResult {
        var b: [String: Any] = ["deviceToken": deviceToken]
        if let d = deviceId { b["deviceId"] = d }
        return try await json(path: "/auth/login-device", method: "POST", body: b)
    }

    public func chatRooms(authBody: [String: Any]) async throws -> JsonResult {
        try await json(path: "/auth/chat-rooms", method: "POST", body: authBody)
    }

    public func getHeartbeatConfig() async throws -> JsonResult {
        try await json(path: "/chat/heartbeat-config", method: "GET", body: nil)
    }

    public func heartbeat(payload: [String: Any]) async throws -> JsonResult {
        try await json(path: "/chat/heartbeat", method: "POST", body: payload)
    }

    public func getPresence() async throws -> JsonResult {
        try await json(path: "/chat/presence", method: "GET", body: nil)
    }
}
