//
//  MP_WebWork.swift
//  MusicPlayer
//
//  Created by Mr.Zhou on 2024/4/30.
//

import Foundation
import WebKit
import Alamofire
///WebView管理器，通过拉取base.js文件来获取解密函数，完成对请求权限的解密
class MP_WebWork:NSObject {
    //单例工具
    static let shared = MP_WebWork()
    ///加载web(调用之后记得销毁)
    private var webView:WKWebView?
    ///油管首页
    private lazy var homePath = "https://music.youtube.com/"
    private var jsPath:String = "https://music.youtube.com/"
    ///解码方法名
    private var codeFunctionName:String!
    ///签名时间缀
    var signatureTimestamp:Int!
    private override init() {
        super.init()
        //实例化webView
        webView = .init(frame: .zero)
        webView?.navigationDelegate = self
        webView?.uiDelegate = self
//        webView?.customUserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
    }
    deinit {
        webView = nil
    }
    /// 访问youtube主页
    func pingYoutubeHome() {
        //实现一个请求
        let request = URLRequest(url: .init(string: homePath)!)
        //加载web
        webView?.load(request)
    }
    ///获取base.js文件地址
    private func getBasePath(_ jsContent:String) {
        let pattern = "s/player/[0-9a-fA-F]{8}/player_ias.vflset/[a-zA-Z_]+/base\\.js"
        guard let regex = try? NSRegularExpression(pattern: pattern, options: .dotMatchesLineSeparators) else {
            print("Regular expression compilation failed")
            return
        }
        // 在整个字符串范围内搜索正则表达式匹配项
        let nsRange = NSRange(jsContent.startIndex..<jsContent.endIndex, in: jsContent)
        let matches = regex.matches(in: jsContent, options: [], range: nsRange)
        // 检查是否找到匹配项
        if let first = matches.first {
            // 从匹配结果中提取整个匹配的字符串
            if let swiftRange = Range(first.range, in: jsContent) {
                let matchedString = String(jsContent[swiftRange])
                //成功获得base.js地址，进行拼接更改
                self.jsPath = self.jsPath + matchedString
                print("Current base.JavaScript path:\(self.jsPath)")
                //开始获取首页内容
                MPPositive_BrowseLoadViewModel.shared.reloadBrowseLists()
                //切换地址
                if let baseUrl = URL(string: self.jsPath) {
                    let request = URLRequest(url: baseUrl)
                    webView?.load(request)
                }
            }
        }
    }
    /// 调用JSweb并解密相关内容
    /// - Parameter signatureString: 需要解密的权限字符串
    func excuteJavaScript(_ signatureString:String, completion:@escaping((String) -> Void)){
        //检索webView是否存在
        guard webView != nil, codeFunctionName != nil else {
            return
        }
        //当webView和解码方法名同时存在时
        let function = "_yt_player.SNa('\(signatureString)');"
        //调用解密方法
        webView?.evaluateJavaScript(function){result,error in
            if let error = error {
                print("Code Error:\(error)")
            }
            if let result = result as? String {
                //该方法返回结果是一个字符串
                completion(result)
            }
        }
    }
    ///获取方法名的正则表达
    private func regexFunction(_ jsContent:String) -> String? {
        var result:String?
        //唯一性的方法字符串
        let pattern = "\\w+=function\\(a\\)\\{[^}]*?a=a\\.split\\(\\\"\\\"\\);"
        // 使用NSRegularExpression进行正则匹配
        guard let regex = try? NSRegularExpression(pattern: pattern, options: .dotMatchesLineSeparators) else {
            print("Regular expression compilation failed")
            return result
        }
        // 执行正则匹配
        let matches = regex.matches(in: jsContent, options: [], range: NSRange(location: 0, length: jsContent.utf16.count))
        // 遍历匹配项并打印函数名
        for match in matches {
            if let range = Range(match.range(at: 0), in: jsContent) {
                // 提取函数体字符串
                let functionbody = String(jsContent[range])
                //将函数体字符串进行截取（以=为基准）
                let results = functionbody.split(separator: "=").map(String.init)
                //第一个元素就是方法名
                result = results[0]
            }
        }
        return result
    }
    ///获取签名时间值
    private func getSignatureTimestamp(_ jsContent:String) -> Int?{
        let regexPattern = "signatureTimestamp:(\\d+)"
        guard let regex = try? NSRegularExpression(pattern: regexPattern, options: .dotMatchesLineSeparators) else {
            print("Regular expression compilation failed")
            return nil
        }
        let range = NSRange(jsContent.startIndex..<jsContent.endIndex, in: jsContent)
        let matches = regex.matches(in: jsContent, options: [], range: range)
        if let first = matches.first {
            if let matchRange = Range(first.range(at: 1), in: jsContent) {
                let matchedNumber = String(jsContent[matchRange])
                print(matchedNumber)
                return Int(matchedNumber)
            }
            return nil
        }
        return nil
    }
}
//MARK: - navigationDelegate
extension MP_WebWork: WKNavigationDelegate, WKUIDelegate {
    func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void){
        guard let url = navigationResponse.response.url, url.lastPathComponent == "base.js", codeFunctionName == nil else {
            decisionHandler(.allow) // 允许非JavaScript文件的加载
            return
        }
        //调用的是base.js文件，拦截该请求
        decisionHandler(.cancel)
        // 使用URLSession重新请求base.js文件
        let task = URLSession.shared.dataTask(with: url){ [weak self] data, response, error in
            guard let self = self, let data = data, error == nil else {
                print("Request base.JavaScript error: \(error?.localizedDescription ?? "")")
                decisionHandler(.allow)
                return
            }
            // 修改JavaScript文件内容
            guard let jsContent = String(data: data, encoding: .utf8) else {
                decisionHandler(.allow)
                return
            }
            guard let function = regexFunction(jsContent), let timeValue = getSignatureTimestamp(jsContent) else {
                decisionHandler(.allow)
                return
            }
            //获取需要的方法名,和签名时间缀
            signatureTimestamp = timeValue
            codeFunctionName = function
            //由于该解密函数方法是私有的，因此创建一句暴露代码
            let code = "g.SNa=\(codeFunctionName!);"
            let pattern = "\(codeFunctionName!)=function\\(a\\)\\{[^\\}]*\\};"
            let regex = try? NSRegularExpression(pattern: pattern, options: .dotMatchesLineSeparators)
            let nsRange = NSRange(jsContent.startIndex..<jsContent.endIndex, in: jsContent)
            let matches = regex?.matches(in: jsContent, options: [], range: nsRange)
            if let match = matches?.first {
                let replacementString = "\(jsContent[Range(match.range, in: jsContent)!])\n\(code)"
                let newJavaScript = jsContent.replacingOccurrences(of: jsContent[Range(match.range, in: jsContent)!], with: replacementString)
                DispatchQueue.main.async {
                    // 在这里处理新的JavaScript代码，例如注入到webView
                    webView.evaluateJavaScript(newJavaScript) { result,error in
                        if let error = error {
                            print("注入代码失败:\(error)")
                        }else {
                            print("注入代码完成")
                            //发布切换启动页
                            NotificationCenter.notificationKey.post(notificationName: .js_edit_completion)
                        }
                    }
                }
            }
        }
        task.resume()
    }

    
    
    // WKNavigationDelegate 方法，用于监听加载完成事件
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        //未加载，查找解码方法
        webView.evaluateJavaScript("document.documentElement.outerHTML", completionHandler: { [weak self] (result, error) in
            //成功抓取了js内容
            if let content = result as? String {
                if self?.jsPath != "https://music.youtube.com/" {
                    //当前base.js文件获取成功，获取解密方法名
                }else {
                    //获取base.js地址
                    self?.getBasePath(content)
                }
            } else if let error = error {
                print("Error getting JavaScript content: \(error.localizedDescription)")
            }
        })
    }

}
