import Foundation

/**
 * HTTP client for making network requests
 *
 * Uses URLSession for reliable networking with automatic retries and caching.
 * All methods are async functions using Swift's async/await.
 */
internal class HTTPClient {

    private let session: URLSession

    init(configuration: URLSessionConfiguration? = nil) {
        let config = configuration ?? {
            let defaultConfig = URLSessionConfiguration.default
            defaultConfig.timeoutIntervalForRequest = 10
            defaultConfig.timeoutIntervalForResource = 10
            return defaultConfig
        }()
        self.session = URLSession(configuration: config)
    }

    /**
     * Perform a GET request
     *
     * - Parameters:
     *   - url: The URL to fetch
     *   - headers: Optional HTTP headers
     * - Returns: Result containing response body or error
     */
    func get(url: String, headers: [String: String] = [:]) async -> Result<String, Error> {
        guard let url = URL(string: url) else {
            let error = NSError(
                domain: "HTTPClient",
                code: -1,
                userInfo: [NSLocalizedDescriptionKey: "Invalid URL: \(url)"]
            )
            BCLogger.error("GET request failed: Invalid URL")
            return .failure(error)
        }

        var request = URLRequest(url: url)
        request.httpMethod = "GET"
        headers.forEach { request.addValue($0.value, forHTTPHeaderField: $0.key) }

        do {
            let (data, response) = try await session.data(for: request)

            guard let httpResponse = response as? HTTPURLResponse else {
                let error = NSError(
                    domain: "HTTPClient",
                    code: -1,
                    userInfo: [NSLocalizedDescriptionKey: "Invalid response type"]
                )
                return .failure(error)
            }

            if (200...299).contains(httpResponse.statusCode) {
                let string = String(data: data, encoding: .utf8) ?? ""
                BCLogger.verbose("GET success: \(url.absoluteString) (\(data.count) bytes)")
                return .success(string)
            } else {
                let error = NSError(
                    domain: "HTTPClient",
                    code: httpResponse.statusCode,
                    userInfo: [NSLocalizedDescriptionKey: "HTTP \(httpResponse.statusCode)"]
                )
                BCLogger.warning("GET failed: \(url.absoluteString) - HTTP \(httpResponse.statusCode)")
                return .failure(error)
            }
        } catch {
            BCLogger.error("GET request failed: \(url.absoluteString) - \(error)")
            return .failure(error)
        }
    }

    /**
     * Perform a POST request
     *
     * - Parameters:
     *   - url: The URL to post to
     *   - body: Request body (JSON string)
     *   - headers: Optional HTTP headers
     * - Returns: Result containing response body or error
     */
    func post(
        url: String,
        body: String,
        headers: [String: String] = [:]
    ) async -> Result<String, Error> {
        guard let url = URL(string: url) else {
            let error = NSError(
                domain: "HTTPClient",
                code: -1,
                userInfo: [NSLocalizedDescriptionKey: "Invalid URL: \(url)"]
            )
            BCLogger.error("POST request failed: Invalid URL")
            return .failure(error)
        }

        // Log the request body for debugging
        BCLogger.debug("POST to: \(url.absoluteString)")
        BCLogger.debug("Request body: \(body)")

        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.httpBody = body.data(using: .utf8)
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        headers.forEach { request.addValue($0.value, forHTTPHeaderField: $0.key) }

        do {
            let (data, response) = try await session.data(for: request)

            guard let httpResponse = response as? HTTPURLResponse else {
                let error = NSError(
                    domain: "HTTPClient",
                    code: -1,
                    userInfo: [NSLocalizedDescriptionKey: "Invalid response type"]
                )
                return .failure(error)
            }

            if (200...299).contains(httpResponse.statusCode) {
                let string = String(data: data, encoding: .utf8) ?? ""
                BCLogger.verbose("POST success: \(url.absoluteString)")
                return .success(string)
            } else {
                // Log response body for 4xx errors to see what the server says
                let errorBody = String(data: data, encoding: .utf8) ?? ""
                let error = NSError(
                    domain: "HTTPClient",
                    code: httpResponse.statusCode,
                    userInfo: [NSLocalizedDescriptionKey: "HTTP \(httpResponse.statusCode)"]
                )
                BCLogger.warning("POST failed: \(url.absoluteString) - HTTP \(httpResponse.statusCode)")
                if !errorBody.isEmpty {
                    BCLogger.warning("Error response body: \(errorBody)")
                }
                return .failure(error)
            }
        } catch {
            BCLogger.error("POST request failed: \(url.absoluteString) - \(error)")
            return .failure(error)
        }
    }
}
