import JavaScriptCore
import Alamofire


import Alamofire
import Foundation
 
//// 扩展SessionManager以支持多个Cookies
//extension SessionManager {
//    static let multipleCookiesSessionManager: SessionManager = {
//        let configuration = URLSessionConfiguration.default
//        configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders
//        
//        let manager = SessionManager(configuration: configuration)
//        
//        // 自定义处理Cookies的方式
//        manager.delegate.taskWillPerformHTTPRedirection = { session, task, response, request in
//            if let headers = response.allHeaderFields as? [String: String],
//               let setCookies = HTTPCookie.cookies(withResponseHeaderFields: headers, for: request.url!) {
//                for cookie in setCookies {
//                    HTTPCookieStorage.shared.setCookie(cookie)
//                }
//            }
//            return request
//        }
//        
//        return manager
//    }()
//}
// 
//// 使用扩展的SessionManager发送请求
//SessionManager.multipleCookiesSessionManager.request("https://www.youtube.com/watch?v=5GJWxDKyk3A").response { response in
//    debugPrint(response)
//}

func downloadJSFile(url: URL, completion: @escaping (Result<String, Error>) -> Void) {
    AF.download(url).responseData { (response) in
        switch response.result {
        case .success(let data):
            if let jsString = String(data: data, encoding: .utf8) {
                completion(.success(jsString))
            } else {
                completion(.failure(NSError(domain: "Download Error", code: -1, userInfo: nil)))
            }
        case .failure(let error):
            completion(.failure(error))
        }
    }
}

func createJSContext() -> JSContext {
    let ctx = JSContext()
    
    // 注入 console.log
    ctx?.evaluateScript("var console = { log: function(message) { _consoleLog(message) } }")
    let consoleLog: @convention(block) (String) -> Void = { message in
        print("JS 打印: \(message)")
    }
    ctx?.setObject(unsafeBitCast(consoleLog, to: AnyObject.self), forKeyedSubscript: "_consoleLog" as (NSCopying & NSObjectProtocol)?)
    
    // 注入AF
    ctx?.evaluateScript("var AF = { request: function(url, method, data, headers, callback) { _request(url, method, data, headers, callback) } }")
    let af: @convention(block) (String, String, String?, [String: String]?, JSValue?) -> Void = { url, method, data, headers, callback in
        var request = URLRequest(url: URL(string: url)!)
        request.httpMethod = method
        
        if method == "POST" {
            if let data = data {
                request.setValue("application/json", forHTTPHeaderField: "Content-Type")
                request.httpBody = data.data(using: .utf8)
            }
        }
        
        if let headers = headers {
            request.headers = HTTPHeaders(headers)
        }
        
        AF.request(request).response { response in
            if let data = response.data {
                var headerJsonString = ""
                if let headers = response.response?.allHeaderFields as? [String: String] {
                    do {
                        let jsonData = try JSONSerialization.data(withJSONObject: headers, options: [])
                        if let jsonString = String(data: jsonData, encoding: .utf8) {
                            headerJsonString = jsonString
                        }
                    } catch {
                        
                    }
                }
                callback?.call(withArguments: [String(data: data, encoding: .utf8), headerJsonString, nil])
            }
            if let error = response.error {
                debugPrint(response)
                callback?.call(withArguments: [nil, nil, error.localizedDescription])
            }
        }
    }
    ctx?.setObject(unsafeBitCast(af, to: AnyObject.self), forKeyedSubscript: "_request" as (NSCopying & NSObjectProtocol)?)
    
    // 捕捉JS运行异常
    ctx?.exceptionHandler = { context, exception in
        if let exception = exception {
            debugPrint(exception)
            print("JS 执行异常: \(exception)")
        }
    }
    
    return ctx!
}

func testDetail(url: String, ctx: JSContext) -> Void {
    let startTime = DispatchTime.now()
    if let detailFunction = ctx.objectForKeyedSubscript("detail") {
        let result = detailFunction.call(withArguments: [url])
        let completionHandler: @convention(block) (JSValue) -> Void = { result in
            print("详情结果!!: \(result.toDictionary())")
            let endTime = DispatchTime.now()
            let nanoTime = endTime.uptimeNanoseconds - startTime.uptimeNanoseconds
            let timeInterval = Double(nanoTime) / 1_000_000_000
            print("耗时: \(timeInterval) seconds")
        }
        let completionFunction = unsafeBitCast(completionHandler, to: AnyObject.self)
        result?.invokeMethod("then", withArguments: [completionFunction])
    }
}

func testSearch(keyword: String, ctx: JSContext) -> Void {
    if let search = ctx.objectForKeyedSubscript("search") {
        let result = search.call(withArguments: [keyword])
        let completionHandler: @convention(block) (JSValue) -> Void = { result in
            print("搜索结果!!: \(result.toDictionary())")
        }
        let completionFunction = unsafeBitCast(completionHandler, to: AnyObject.self)
        result?.invokeMethod("then", withArguments: [completionFunction])
    }
}

let ctx = createJSContext()

let remote = "https://d3crpuooyqht8f.cloudfront.net/dc1ff45a-5823-45c8-8245-331c4b4be0b4"
let local = "file:///Users/ben/Desktop/app/be/be-ytb/js/bundle.js"

if let url = URL(string: remote) {
    downloadJSFile(url: url) { result in
        switch result {
        case .success(let jsString):
            print("下载远程JS成功")
            ctx.evaluateScript(jsString)
            testDetail(url: "https://www.youtube.com/watch?v=U1th94xR694", ctx: ctx)
//            testSearch(keyword: "周杰伦", ctx: ctx)
        case .failure(let error):
            print("Download Error: \(error)")
        }
    }
}

RunLoop.main.run()
