import Foundation

/// Ejemplos de uso de APIConfig
///
/// Este archivo demuestra cómo utilizar la configuración de la API
/// en diferentes escenarios de la aplicación.
class APIConfigExample {

    /// Ejemplo 1: Configurar URLSession con timeouts de APIConfig
    func configureURLSession() -> URLSession {
        let configuration = URLSessionConfiguration.default
        configuration.timeoutIntervalForRequest = APIConfig.defaultTimeout
        configuration.timeoutIntervalForResource = APIConfig.downloadTimeout
        return URLSession(configuration: configuration)
    }

    /// Ejemplo 2: Construir una URL completa para un endpoint
    func buildEndpointURL() {
        // Método 1: Usar la función helper
        let url1 = APIConfig.url(for: "manga/popular")
        print("URL completa: \(url1)")

        // Método 2: Usar urlObject para obtener un objeto URL
        if let url2 = APIConfig.urlObject(for: "manga/popular") {
            print("URL object: \(url2)")
        }

        // Método 3: Usar directamente baseURL
        let url3 = "\(APIConfig.basePath)/manga/popular"
        print("URL manual: \(url3)")
    }

    /// Ejemplo 3: Usar los endpoints predefinidos
    func usePredefinedEndpoints() {
        // Endpoint de descarga
        let downloadURL = APIConfig.Endpoints.download(
            mangaSlug: "one-piece",
            chapterNumber: 1089
        )
        print("Download endpoint: \(downloadURL)")

        // Endpoint de verificación
        let checkURL = APIConfig.Endpoints.checkDownloaded(
            mangaSlug: "one-piece",
            chapterNumber: 1089
        )
        print("Check endpoint: \(checkURL)")

        // Endpoint de imagen
        let imageURL = APIConfig.Endpoints.getImage(
            mangaSlug: "one-piece",
            chapterNumber: 1089,
            pageIndex: 0
        )
        print("Image endpoint: \(imageURL)")

        // Endpoint de health check
        let healthURL = APIConfig.Endpoints.health()
        print("Health endpoint: \(healthURL)")

        // Endpoint de estadísticas de almacenamiento
        let statsURL = APIConfig.Endpoints.storageStats()
        print("Storage stats endpoint: \(statsURL)")
    }

    /// Ejemplo 4: Crear una URLRequest con headers comunes
    func createRequest() -> URLRequest? {
        let endpoint = "manga/popular"

        guard let url = APIConfig.urlObject(for: endpoint) else {
            return nil
        }

        var request = URLRequest(url: url)
        request.timeoutInterval = APIConfig.defaultTimeout

        // Añadir headers comunes
        for (key, value) in APIConfig.commonHeaders {
            request.setValue(value, forHTTPHeaderField: key)
        }

        // Si se requiere autenticación
        // let token = "your-auth-token"
        // let authHeaders = APIConfig.authHeader(token: token)
        // for (key, value) in authHeaders {
        //     request.setValue(value, forHTTPHeaderField: key)
        // }

        return request
    }

    /// Ejemplo 5: Validar la configuración al iniciar la app
    func validateConfiguration() {
        #if DEBUG
        // Imprimir configuración en debug
        APIConfig.printConfiguration()
        #endif

        // Validar que la configuración sea correcta
        guard APIConfig.isValid else {
            print("ERROR: Configuración de API inválida")
            return
        }

        print("Configuración válida: \(APIConfig.baseURL)")
    }

    /// Ejemplo 6: Hacer una request simple
    func makeSimpleRequest() async throws {
        let endpoint = "manga/popular"
        guard let url = APIConfig.urlObject(for: endpoint) else {
            print("URL inválida")
            return
        }

        var request = URLRequest(url: url)
        request.timeoutInterval = APIConfig.timeoutFor(isResourceRequest: false)

        for (key, value) in APIConfig.commonHeaders {
            request.setValue(value, forHTTPHeaderField: key)
        }

        let (data, response) = try await URLSession.shared.data(for: request)

        if let httpResponse = response as? HTTPURLResponse {
            print("Status code: \(httpResponse.statusCode)")
        }

        // Procesar data...
        print("Recibidos \(data.count) bytes")
    }

    /// Ejemplo 7: Usar timeouts apropiados según el tipo de request
    func demonstrateTimeouts() {
        // Request normal (usar defaultTimeout)
        let normalTimeout = APIConfig.timeoutFor(isResourceRequest: false)
        print("Normal timeout: \(normalTimeout)s") // 30.0s

        // Request de descarga de imagen (usar downloadTimeout)
        let resourceTimeout = APIConfig.timeoutFor(isResourceRequest: true)
        print("Resource timeout: \(resourceTimeout)s") // 300.0s
    }

    /// Ejemplo 8: Cambiar configuración según el entorno
    func configureForEnvironment() {
        #if DEBUG
        // En desarrollo, usar configuración local
        print("Modo desarrollo")
        // Nota: Para cambiar realmente la configuración, modificar las propiedades
        // estáticas en APIConfig usando compilación condicional
        #else
        // En producción, usar configuración de producción
        print("Modo producción")
        #endif
    }

    /// Ejemplo 9: Manejar errores específicos de la API
    func handleAPIError(errorCode: Int) {
        switch errorCode {
        case APIConfig.ErrorCodes.chapterNotFound:
            print("Capítulo no encontrado")
        case APIConfig.ErrorCodes.chapterAlreadyDownloaded:
            print("Capítulo ya descargado")
        case APIConfig.ErrorCodes.storageLimitExceeded:
            print("Límite de almacenamiento excedido")
        case APIConfig.ErrorCodes.invalidImageFormat:
            print("Formato de imagen inválido")
        case APIConfig.ErrorCodes.downloadFailed:
            print("Descarga fallida")
        default:
            print("Error desconocido: \(errorCode)")
        }
    }

    /// Ejemplo 10: Implementar retry con backoff exponencial
    func fetchWithRetry(endpoint: String, retryCount: Int = 0) async throws -> Data {
        guard let url = APIConfig.urlObject(for: endpoint) else {
            throw URLError(.badURL)
        }

        var request = URLRequest(url: url)
        request.timeoutInterval = APIConfig.defaultTimeout

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

            if let httpResponse = response as? HTTPURLResponse,
               httpResponse.statusCode == 200 {
                return data
            } else {
                throw URLError(.badServerResponse)
            }
        } catch {
            // Verificar si debemos reintentar
            if retryCount < APIConfig.maxRetries {
                // Calcular delay con backoff exponencial
                let delay = APIConfig.baseRetryDelay * pow(2.0, Double(retryCount))
                print("Retry \(retryCount + 1) después de \(delay)s")

                try await Task.sleep(nanoseconds: UInt64(delay * 1_000_000_000))

                return try await fetchWithRetry(endpoint: endpoint, retryCount: retryCount + 1)
            } else {
                throw error
            }
        }
    }
}

// MARK: - Usage Examples

// Ejemplo de uso en una ViewModel o Service:
class MangaServiceExample {

    func fetchPopularManga() async throws {
        // Usar endpoint predefinido
        let endpoint = "manga/popular"
        guard let url = APIConfig.urlObject(for: endpoint) else {
            return
        }

        var request = URLRequest(url: url)
        request.timeoutInterval = APIConfig.defaultTimeout

        // Añadir headers
        for (key, value) in APIConfig.commonHeaders {
            request.setValue(value, forHTTPHeaderField: key)
        }

        // Hacer request
        let (data, _) = try await URLSession.shared.data(for: request)

        // Parsear respuesta...
        print("Datos recibidos: \(data.count) bytes")
    }

    func downloadChapter(mangaSlug: String, chapterNumber: Int) async throws {
        // Usar endpoint predefinido
        let endpoint = APIConfig.Endpoints.download(
            mangaSlug: mangaSlug,
            chapterNumber: chapterNumber
        )

        guard let url = URL(string: endpoint) else {
            return
        }

        var request = URLRequest(url: url)
        // Usar timeout más largo para descargas
        request.timeoutInterval = APIConfig.downloadTimeout

        for (key, value) in APIConfig.commonHeaders {
            request.setValue(value, forHTTPHeaderField: key)
        }

        // Hacer request
        let (data, response) = try await URLSession.shared.data(for: request)

        if let httpResponse = response as? HTTPURLResponse {
            print("Status: \(httpResponse.statusCode)")

            // Manejar errores específicos
            if httpResponse.statusCode != 200 {
                // Aquí podrías usar APIConfig.ErrorCodes si el backend
                // retorna códigos de error personalizados
                throw URLError(.badServerResponse)
            }
        }

        print("Descarga completada: \(data.count) bytes")
    }

    func checkServerHealth() async throws {
        // Usar endpoint de health check
        let endpoint = APIConfig.Endpoints.health()

        guard let url = URL(string: endpoint) else {
            return
        }

        var request = URLRequest(url: url)
        request.timeoutInterval = APIConfig.defaultTimeout

        let (_, response) = try await URLSession.shared.data(for: request)

        if let httpResponse = response as? HTTPURLResponse {
            print("Server health status: \(httpResponse.statusCode)")
        }
    }
}
