//
//  LoginState.swift
//  punchnet
//
//  Created by 安礼成 on 2026/1/16.
//

import Foundation
import Observation

@Observable
class UserContext {
    var isLogined: Bool = false
    var loginCredit: Credit?
    var networkSession: NetworkSession?
    
    enum Credit {
        case token(token: String)
        case accountAndPasword(account: String, password: String)
    }
    
    // 登陆后的网络会话信息
    struct NetworkSession: Codable {
        struct ExitNode: Codable {
            let nnid: Int
            let nodeName: String
            
            enum CodingKeys: String, CodingKey {
                case nnid
                case nodeName = "node_name"
            }
        }
        
        let accessToken: String
        let username: String
        let userType: String
        let audit: Int
        let networkId: Int
        let networkName: String
        let networkDomain: String
        let exitNodes: [ExitNode]
        
        enum CodingKeys: String, CodingKey {
            case accessToken = "access_token"
            case username
            case userType = "user_type"
            case audit
            case networkId = "network_id"
            case networkName = "network_name"
            case networkDomain = "network_domain"
            case exitNodes = "exit_node"
        }
    }
    
    private let baseParams: [String: Any] = [
        "client_id": SystemConfig.getClientId(),
        "mac": SystemConfig.macAddressString(mac: SystemConfig.getMacAddress())
    ]
    
    @MainActor
    func loginWithAccountAndPassword(username: String, password: String) async throws {
        var params: [String: Any] = [
            "username": username,
            "password": password,
        ]
        params.merge(baseParams) {$1}
        
        self.networkSession = try await SDLAPIClient.doPost(path: "/auth/login", params: params, as: NetworkSession.self)
        self.loginCredit = .accountAndPasword(account: username, password: password)
        self.isLogined = true
        
        // 将数据缓存到keychain
        if let data = "\(username):\(password)".data(using: .utf8) {
            try KeychainStore.shared.save(data, account: "accountAndPasword")
        }
    }
    
    @MainActor
    func loginWithToken(token: String) async throws {
        var params: [String: Any] = [
            "token": token,
        ]
        params.merge(baseParams) {$1}
        
        self.networkSession = try await SDLAPIClient.doPost(path: "/auth/token", params: params, as: NetworkSession.self)
        self.loginCredit = .token(token: token)
        self.isLogined = true
        
        // 将数据缓存到keychain
        if let data = token.data(using: .utf8) {
            try KeychainStore.shared.save(data, account: "token")
        }
    }
    
    @MainActor
    func sendVerifyCode(username: String) async throws -> String {
        var params: [String: Any] = [
            "username": username
        ]
        params.merge(baseParams) {$1}
        
        return try await SDLAPIClient.doPost(path: "/auth/sendVerifyCode", params: params, as: String.self)
    }
    
    func loadCacheToken() -> String? {
        if let data = try? KeychainStore.shared.load(account: "token") {
            return String(data: data, encoding: .utf8)
        }
        return nil
    }
    
    func loadCacheUsernameAndPassword() -> (String, String)? {
        if let data = try? KeychainStore.shared.load(account: "accountAndPasword"),
            let str = String(data: data, encoding: .utf8) {
            let parts = str.split(separator: ":")
            if parts.count == 2 {
                return (String(parts[0]), String(parts[1]))
            }
        }
        return nil
    }
    
}
