//
//  NetworkManager.swift
//  WOKA
//
//  Created by MacBook Pro on 06/05/24.
//

import Alamofire

class NetworkManager{
    
    static let shareInstance = NetworkManager()
    private let alamofireLogger = AlamofireLogger()

    private init() {}
    
    enum APIError: Error {
        case networkError
        case noNetwork(message:String)
        case invalidURL
        case parameterEncodingFailed
        case responseValidationFailed
        case unknown(message: String)
        case custom(message: String)
    }
    
    /// This function will do the network call for HTTPMethod & Encoding is URLEncoding with contentType ["application/json"]
    ///
    ///
    /// - Warning: The returned string is not localized.
    ///
    /// Usage:
    ///
    ///     Alamofire network call Generic (.get , .post, .put.).
    ///
    /// - Parameter (header : HTTPHeaders , Params :[String : Any] , URL , Dedocable Generic T Struct. , queue : dispatchQueue decide)
    /// - NOTE Oncompletion will be called on main thread so no need to specify the main thread for UI updates
    /// - Returns: This function returns a GENERIC response base on the T Model & APIError .
    func apiRequest<T: Codable>(
        url: URLConvertible,
        method: HTTPMethod,
        parameters: Parameters? = nil,
        encoding: ParameterEncoding = URLEncoding.default,
        headers: HTTPHeaders? = nil,
        queue: DispatchQueue = QueueHelper.background,
        completionHandler: @escaping (Result<T, APIError>) -> Void
    ) {
        // Stop monitoring network reachability
        NetworkReachibility.shared.stopMonitoring()

        // Execute the request on the specified queue
        queue.async {
            AF.request(url, method: method, parameters: parameters, encoding: encoding, headers: headers, requestModifier: { $0.timeoutInterval = 30 })
                .authenticate(username: "admin", password: "Woka@1234")
                .validate(statusCode: 200..<300)
                .responseDecodable(of: T.self) { response in
//                    alamofireLogger.request(response.da, didParseResponse: response)
                    switch response.result {
                    case .success(let value):
                        // Handle successful response on the main thread
                        DispatchQueue.main.async {
                            completionHandler(.success(value))
                        }
                    case .failure(let error):
                        // Handle failure cases
                        if let afError = error as? AFError {
                            switch afError {
                            case .sessionTaskFailed(let urlError):
                                if urlError._code == -1020 || urlError._code == -1009 {
                                    // Handle network error on the main thread
                                    DispatchQueue.main.async {
                                        completionHandler(.failure(.noNetwork(message: K.ConstantString.noInternet)))
                                    }
                                } else {
                                    // Handle other network errors on the main thread
                                    DispatchQueue.main.async {
                                        completionHandler(.failure(.networkError))
                                    }
                                }
                            case .invalidURL:
                                // Handle invalid URL error on the main thread
                                DispatchQueue.main.async {
                                    completionHandler(.failure(.invalidURL))
                                }
                            case .parameterEncodingFailed:
                                // Handle parameter encoding failure on the main thread
                                DispatchQueue.main.async {
                                    completionHandler(.failure(.parameterEncodingFailed))
                                }
                            case .responseValidationFailed:
                                // Handle response validation failure on the main thread
                                DispatchQueue.main.async {
                                    completionHandler(.failure(.responseValidationFailed))
                                }
                            default:
                                // Handle other network errors on the main thread
                                DispatchQueue.main.async {
                                    completionHandler(.failure(.networkError))
                                }
                            }
                        } else {
                            // Handle unrecognized errors on the main thread
                            DispatchQueue.main.async {
                                completionHandler(.failure(.unknown(message: K.ConstantString.unRecognised)))
                            }
                        }
                    }
                }
        }
    }
}


final class AlamofireLogger: EventMonitor {

    func requestDidResume(_ request: Request) {

        let allHeaders = request.request.flatMap { $0.allHTTPHeaderFields.map { $0.description } } ?? "None"
        let headers = """
        ⚡️⚡️⚡️⚡️ Request Started: \(request)
        ⚡️⚡️⚡️⚡️ Headers: \(allHeaders)
        """
        NSLog(headers)


        let body = request.request.flatMap { $0.httpBody.map { String(decoding: $0, as: UTF8.self) } } ?? "None"
        let message = """
        ⚡️⚡️⚡️⚡️ Request Started: \(request)
        ⚡️⚡️⚡️⚡️ Body Data: \(body)
        """
        NSLog(message)
    }

    func request<Value>(_ request: DataRequest, didParseResponse response: AFDataResponse<Value>) {

        NSLog("⚡️⚡️⚡️⚡️ Response Received: \(response.debugDescription)")
        NSLog("⚡️⚡️⚡️⚡️ Response All Headers: \(String(describing: response.response?.allHeaderFields))")
    }
}
