//
//  ApiFactory.swift
//  iKeyMon
//
//  Created by tracer on 13.11.25.
//

import Foundation

enum APIVersion: String, CaseIterable {
    case v2_12 = "2.12"
    case v2_13 = "2.13"
    case v2_14 = "2.14"
    
    static func from(versionString: String) -> APIVersion? {
        if let version = APIVersion(rawValue: versionString) {
            return version
        }
        
        let components = versionString.split(separator: ".").compactMap { Int($0) }
        guard components.count >= 2 else { return nil }
        
        let major = components[0]
        let minor = components[1]
        
        switch (major, minor) {
        case (2, 12): return .v2_12
        case (2, 13): return .v2_13
        case (2, 14...): return .v2_14
        default: return nil
        }
    }
}

protocol AnyServerAPI {
    func fetchSystemInfo() async throws -> SystemInfo
    func fetchLoadData() async throws -> Any
    func fetchMemoryData() async throws -> Any
    func fetchUtilizationData() async throws -> Any
    func fetchServerSummary(apiKey: String) async throws -> ServerInfo
    func restartServer(apiKey: String) async throws
}

private struct AnyServerAPIWrapper<T: ServerAPIProtocol>: AnyServerAPI {
    private let wrapped: T
    
    init(_ wrapped: T) {
        self.wrapped = wrapped
    }
    
    func fetchSystemInfo() async throws -> SystemInfo {
        return try await wrapped.fetchSystemInfo()
    }
    
    func fetchLoadData() async throws -> Any {
        return try await wrapped.fetchLoad()
    }
    
    func fetchMemoryData() async throws -> Any {
        return try await wrapped.fetchMemory()
    }
    
    func fetchUtilizationData() async throws -> Any {
        return try await wrapped.fetchUtilization()
    }

    func fetchServerSummary(apiKey: String) async throws -> ServerInfo {
        return try await wrapped.fetchServerSummary(apiKey: apiKey)
    }

    func restartServer(apiKey: String) async throws {
        try await wrapped.restartServer(apiKey: apiKey)
    }
}

class APIFactory {
    static func createAPI(baseURL: URL, version: APIVersion) -> AnyServerAPI {
        switch version {
        case .v2_12:
            return AnyServerAPIWrapper(APIv2_12(baseURL: baseURL))
        case .v2_13:
            return AnyServerAPIWrapper(APIv2_13(baseURL: baseURL))
        case .v2_14:
            return AnyServerAPIWrapper(APIv2_14(baseURL: baseURL))
        }
    }
    
    static func createAPI(baseURL: URL, versionString: String) -> AnyServerAPI? {
        guard let version = APIVersion.from(versionString: versionString) else { return nil }
        return createAPI(baseURL: baseURL, version: version)
    }
    
    static func detectAndCreateAPI(baseURL: URL, apiKey: String? = nil) async throws -> AnyServerAPI {
        if let apiKey, !apiKey.isEmpty {
            do {
                let versionURL = baseURL.appendingPathComponent("api/v2/server")
                var request = URLRequest(url: versionURL)
                request.httpMethod = "GET"
                request.setValue(apiKey, forHTTPHeaderField: "X-API-KEY")
                request.timeoutInterval = 15

                let (data, response) = try await URLSession.shared.data(for: request)
                if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 {
                    let decoder = JSONDecoder()
                    decoder.keyDecodingStrategy = .convertFromSnakeCase
                    let probe = try decoder.decode(ServerMetaProbe.self, from: data)
                    if let api = createAPI(baseURL: baseURL, versionString: probe.meta.apiVersion) {
                        return api
                    }
                }
            } catch {
                // Fall back to default version below
            }
        }

        return AnyServerAPIWrapper(APIv2_14(baseURL: baseURL))
    }
}

private struct ServerMetaProbe: Decodable {
    struct Meta: Decodable {
        let apiVersion: String
    }

    let meta: Meta
}
