//
//  KMAIRequestServerManager.swift
//  PDF Reader Pro Edition
//
//  Created by wanjun on 2024/1/17.
//

import Cocoa
import AFNetworking

@objcMembers
class ResultWrapper: NSObject {
    var success: Bool = false
    var result: NSDictionary = [:]
//    var message: String = ""
//    var code : Int = 200
//    var error: NSError?
//    var state: KMAIRewritingState = .rewrite
    var content: String = ""

//    init(success: Bool, result: NSDictionary, message: String, code: Int, error: NSError? = nil, state: KMAIRewritingState) {
//        self.success = success
//        self.result = result
//        self.message = message
//        self.code = code
//        self.error = error
//        self.state = state
//    }
    init(success: Bool, content: String) {
        self.success = success
        self.content = content
        self.result = NSDictionary.init()
    }
    
    init(success: Bool, resultData: NSDictionary) {
        self.success = success
        self.content = ""
        self.result = resultData
    }
}

@objc enum KMAIRewritingState : Int {
    case rewrite = 0        // 重写
    case correctTypos       // 纠错
    case uploadTranslate    // 翻译上传文件
    case fileTranslate      // 翻译文件
    case textTranslate      // 翻译文本
    case extractSummaryFile //摘要
}

@objc enum KMAIFileUploadState : Int {
    case Translation = 0
    case ExtractAbstract
}

//typealias KMRequestServerComplete = (_ success: Bool, _ result: Result?) -> Void

@objcMembers class KMAIRequestServerManager: NSObject {
    static let defaultManager = KMAIRequestServerManager()
    typealias KMRequestServerComplete = (_ wrapper: ResultWrapper) -> Void
    private var downFileUrl: String = "" // 文件翻译
    var downFileName: String = "" // 文件翻译
    
    var fromLanguages: [String] = ["Automatic", "English", "Simplified Chinese", "Traditional Chinese", "Japanese", "Korean", "French", "Spanish", "Italian", "German", "Portuguese", "Russian", "Vietnamese", "Thai", "Arabic", "Greek", "Bulgarian", "Finnish", "Slovene", "Dutch", "Czech", "Swedish", "Polish", "Danish", "Romanian", "Hungarian"]
    var toLanguages: [String] = ["English", "Simplified Chinese", "Traditional Chinese", "Japanese", "Korean", "French", "Spanish", "Italian", "German", "Portuguese", "Russian", "Vietnamese", "Thai", "Arabic", "Greek", "Bulgarian", "Finnish", "Slovene", "Dutch", "Czech", "Swedish", "Polish", "Danish", "Romanian", "Hungarian"]
    
    // MARK: AI Action (public)
    
    func aiAction(content: String, state: KMAIRewritingState, from: String = "auto", to: String = "en", complete: @escaping KMRequestServerComplete) {
        if state == .rewrite || state == .correctTypos {  //重写 && 纠错
            aiRewriting(content: content, state: state, complete: complete)
        } else if state == .uploadTranslate || state == .fileTranslate {    // 上传文件 || 文件翻译
            aiTranslationFileUpload(file: content, complete: { [unowned self] wrapper in
                let success: Bool = wrapper.success
                let fileKey = wrapper.content
                if success {
                    let fileData = wrapper.result
                    complete(wrapper)
//                    aiTranslationFileTranslateHandle(fileKey: fileKey, from: languageAbbreviation(from), to: languageAbbreviation(to), complete: complete)
                } else {
                    complete(wrapper)
                }
            })
        } else if state == .textTranslate { // 文本翻译
            aiTranslationTextTrans(q: content, from: languageAbbreviation(from), to: languageAbbreviation(to), complete: complete)
        } else if state == .extractSummaryFile {    // 提取摘要
            extractSummaryFile(file: content, complete: complete)
        }
    }
    
    // MARK: Private
    
    private func uuid() -> String {
        return GetHardwareUUID()!
    }
    
    private func platform() -> String {
        var platform = "DMG"
#if VERSION_DMG
        platform = "DMG"
#else
        platform = "AiStore"
#endif
        return platform
    }
    
    private func app_name() -> String {
        var bundleID: String!
        bundleID = Bundle.main.object(forInfoDictionaryKey: "CFBundleIdentifier") as! String
        return bundleID;
    }
    
    func downloadFile(filePath: String, downFileName: String, toPath: String, complete: @escaping KMRequestServerComplete) {
        self.downFileUrl = ""
        guard let fileURL = URL(string: filePath) else {
            let alert = NSAlert()
            alert.alertStyle = .critical
            alert.messageText = NSLocalizedString("Invalid file link", comment: "")
            alert.runModal()

            return
        }
        var destinationURL = FileManager.default.temporaryDirectory.appendingPathComponent(downFileName)
        if URL(fileURLWithPath: toPath) != nil {
            destinationURL = URL(fileURLWithPath: toPath)
        }
        if FileManager.default.fileExists(atPath: destinationURL.path) {
            do {
                try FileManager.default.removeItem(at: destinationURL)
                print("删除旧文件成功")
            } catch {
                print("删除旧文件失败:\(error)")
            }
        }
        let sessionConfiguration = URLSessionConfiguration.default
        let session = URLSession(configuration: sessionConfiguration)
        let downloadTask = session.downloadTask(with: fileURL) { (tempLocalURL, response, error) in
            if let error = error {
                let alert = NSAlert()
                alert.alertStyle = .critical
                alert.messageText = String(format: "%@:\(error)", NSLocalizedString("Download failed", comment: ""))
                alert.runModal()
                
                return
            }

            guard let tempLocalURL = tempLocalURL else {
                let alert = NSAlert()
                alert.alertStyle = .critical
                alert.messageText = NSLocalizedString("Invalid temporary directory", comment: "")
                alert.runModal()

                return
            }
            

            do {
                try FileManager.default.moveItem(at: tempLocalURL, to: destinationURL)
                
                let wrapper = ResultWrapper(success: true, content: "")
                wrapper.content = destinationURL.path
                complete(wrapper)
            } catch {
                let alert = NSAlert()
                alert.alertStyle = .critical
                alert.messageText = String(format: "%@:\(error)", NSLocalizedString("Failed to save file", comment: ""))
                alert.runModal()
            }
        }
        self.downFileUrl = destinationURL.path
        downloadTask.resume()
    }
    
    private func languageAbbreviation(_ language: String) -> String {
        if language == "Automatic" || language == "auto" {
            return "auto"
        } else if language == "English" || language == "en" {
            return "en"
        } else if language == "Simplified Chinese" || language == "zh" {
            return "zh"
        } else if language == "Traditional Chinese" || language == "cht" {
            return "cht"
        } else if language == "Japanese" || language == "jp" {
            return "jp"
        } else if language == "Korean" || language == "kor" {
            return "kor"
        } else if language == "French" || language == "fra" {
            return "fra"
        } else if language == "Spanish" || language == "spa" {
            return "spa"
        } else if language == "Italian" || language == "it" {
            return "it"
        } else if language == "German" || language == "de" {
            return "de"
        } else if language == "Portuguese" || language == "pt" {
            return "pt"
        } else if language == "Russian" || language == "ru" {
            return "ru"
        } else if language == "Vietnamese" || language == "vie" {
            return "vie"
        } else if language == "Thai" || language == "th" {
            return "th"
        } else if language == "Arabic" || language == "ara" {
            return "ara"
        } else if language == "Greek" || language == "el" {
            return "el"
        } else if language == "Bulgarian" || language == "bul" {
            return "bul"
        } else if language == "Finnish" || language == "fin" {
            return "fin"
        } else if language == "Slovene" || language == "slo" {
            return "slo"
        } else if language == "Dutch" || language == "nl" {
            return "nl"
        } else if language == "Czech" || language == "cs" {
            return "cs"
        } else if language == "Swedish" || language == "swe" {
            return "swe"
        } else if language == "Polish" || language == "pl" {
            return "pl"
        } else if language == "Danish" || language == "dan" {
            return "dan"
        } else if language == "Romanian" || language == "rom" {
            return "rom"
        } else if language == "Hungarian" || language == "hu" {
            return "hu"
        }
        return "auto"
    }
    
    // MARK: AI Action (private)
    
    /**
     @abstract 翻译上传
     @param file  文件路径
     @param complete 上传完成回调
     */
    private func aiTranslationFileUpload(file: String, complete: @escaping KMRequestServerComplete) {
        let infoDictionary = Bundle .main.infoDictionary!
        let urlString = AIInfoConfig().aiActionURL + "/api/AI/uploadTranslate"
        let fileData = FileManager.default.contents(atPath: file)
        let params: [String: Any] = ["file": fileData,
                                     "uuid": uuid(),
                                     "platform": platform(),
                                     "app_name": app_name(),
                                     "calculate":"1"]
        KMAIRequestServer.requestServer.uploadFile(urlString: urlString, params: params) { formData in
            let fileURL = URL(fileURLWithPath: file)
            try? formData.appendPart(withFileURL: fileURL, name: "file", fileName: fileURL.lastPathComponent, mimeType: "application/octet-stream")
        } requestSerializer: { requestSerializer in
            requestSerializer.setValue("Apifox/1.0.0 (https://www.apifox.cn)", forHTTPHeaderField: "User-Agent")
        } completion: { task, responseObject, error in
            if responseObject != nil {
                let data: NSDictionary = responseObject!["data"] as? NSDictionary ?? [:]
                var code: String = responseObject!["code"] as? String ?? "06005"
                if code == "06005" {
                    let tempCode: Int = responseObject!["code"] as? Int ?? 0
                    if tempCode == 501 {
                        code = "501"
                    }
                }
                
                let message: String = responseObject!["message"] as? String ?? "unknown error"
                let error = NSError(domain: message, code: Int(code)!)
//                let result = ResultWrapper(success: true, result: data, message: message, code: Int(code)!, error: error, state: .uploadTranslate)
//                if result.code == 200 {
//                    result.success = true
//                    complete(result)
//                } else {
//                    result.success = false
//                    complete(result)
//                }
                if Int(code)! == 200 {
                    let wrapper = ResultWrapper(success: true, resultData: data)
                    wrapper.content = data["fileKey"] as! String
                    complete(wrapper)
                } else {
                    let wrapper = ResultWrapper(success: false, resultData: data)
                    if Int(code)! == 501 {
                        wrapper.content = "501"
                    } else {
                        wrapper.content = message
                    }
                    complete(wrapper)
                }
            } else {
//                let error = NSError(domain: "unknown error", code: 404)
//                let result = ResultWrapper(success: false, result: [:], message: "unknown error", code: 404, error: error, state: .uploadTranslate)
//                complete(result)
                complete(ResultWrapper(success: false, content: "unknown error"))
            }
        }
    }
    
    /**
     @abstract 文件翻译
     @param fileKey  文件Key
     @param from 初始语言
     @param to 结束语言
     */
    func aiTranslationFileTranslateHandle(fileKey: String, from: String, to: String, complete: @escaping KMRequestServerComplete) {
        
        let infoDictionary = Bundle .main.infoDictionary!
        let urlString = AIInfoConfig().aiActionURL + "/api/AI/fileTranslate"

        let paraDict = ["fileKey": fileKey,
                        "from": languageAbbreviation(from),
                        "to": languageAbbreviation(to),
                        "uuid": uuid(),
                        "platform": platform(),
                        "app_name": app_name()]
        var postData  = try! JSONSerialization.data(withJSONObject: paraDict)

        
        var request = URLRequest(url: URL(string: urlString)!,timeoutInterval: Double.infinity)
        request.addValue("Apifox/1.0.0 (https://www.apifox.cn)", forHTTPHeaderField: "User-Agent")
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")

        request.httpMethod = "POST"
        request.httpBody = postData

        let task = URLSession.shared.dataTask(with: request) { data, response, error in
           guard let data = data else {
               print(String(describing: error))
               return
           }
            let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []) as? NSDictionary ?? [:]
            if jsonObject != nil {
                let data1: NSDictionary = jsonObject!["data"] as? NSDictionary ?? [:]
                let code: String = jsonObject!["code"] as? String ?? "06005"
                let message: String = jsonObject!["message"] as? String ?? "unknown error"
                let error = NSError(domain: message, code: Int(code)!)
//                let result = ResultWrapper(success: true, result: data1, message: message, code: Int(code)!, error: error, state: .fileTranslate)
//                if result.code == 200 {
//                    result.success = true
//                    complete(result)
//                } else {
//                    result.success = false
//                    complete(result)
//                }
                if Int(code)! == 200 {
                    let fileUrl = data1["fileUrl"]
                    let downFileUrl = data1["downFileUrl"]
                    let ossDownUrl = data1["ossDownUrl"]
                    let fileName = data1["fileName"]
                    let downFileName = data1["downFileName"]
                    let fromStr = data1["from"]
                    let toStr = data1["to"]
                    
                    self.downFileName = downFileName as! String
//                    self.downloadFile(filePath: ossDownUrl as! String, downFileName: downFileName as! String)
                    complete(ResultWrapper(success: true, content: ossDownUrl as! String))
                } else {
                    complete(ResultWrapper(success: false, content: message))
                }
            } else {
//                let error = NSError(domain: "unknown error", code: 404)
//                let result = ResultWrapper(success: false, result: [:], message: "unknown error", code: 404, error: error, state: .fileTranslate)
//                complete(result)
                complete(ResultWrapper(success: false, content: "unknown error"))
            }
        }
        task.resume()
    }

    /**
     @abstract 内容翻译
     @param q  选中
     @param from 初始语言
     @param to 结束语言
     */
    private func aiTranslationTextTrans(q: String, from: String, to: String, complete: @escaping KMRequestServerComplete) {
        
        let infoDictionary = Bundle .main.infoDictionary!
        let urlString = AIInfoConfig().aiActionURL + "/api/AI/textTranslate"
        
        var escapedString = q
        escapedString = String(data: escapedString.data(using: .utf8)!, encoding: .utf8)!
        let paraDict = ["text":escapedString,
                        "from":from,
                        "to":to,
                        "uuid":uuid(),
                        "platform": platform(),
                        "app_name": app_name()]
        var postData  = try! JSONSerialization.data(withJSONObject: paraDict)

        var request = URLRequest(url: URL(string: urlString)!,timeoutInterval: Double.infinity)
        request.addValue("Apifox/1.0.0 (https://www.apifox.cn)", forHTTPHeaderField: "User-Agent")
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")

        request.httpMethod = "POST"
        request.httpBody = postData

        let task = URLSession.shared.dataTask(with: request) { data, response, error in
           guard let data = data else {
               print(String(describing: error))
               return
           }
            let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []) as? NSDictionary ?? [:]
            if jsonObject != nil {
                let data1: NSDictionary = jsonObject!["data"] as? NSDictionary ?? [:]
                let code: String = jsonObject!["code"] as? String ?? "06005"
                let message: String = jsonObject!["message"] as? String ?? "unknown error"
                let error = NSError(domain: message, code: Int(code)!)
                if Int(code)! == 200 {
                    var resultStr = data1["dst"] as! String
                    complete(ResultWrapper(success: true, content: resultStr))
                } else {
                    complete(ResultWrapper(success: false, content: message))
                }
            } else {
                complete(ResultWrapper(success: false, content: "unknown error"))
            }
        }
        task.resume()
    }
    
    /**
     @abstract重写 & 纠错
     @param content  内容
     @param state  类型
     */
    private func aiRewriting(content: String, state: KMAIRewritingState, complete: @escaping KMRequestServerComplete) {
        
        var urlString = AIInfoConfig().aiActionURL + "/api/AI/rewrite"
        if state == .correctTypos {
            urlString = AIInfoConfig().aiActionURL + "/api/AI/correctTypos"
        }
        let params: [String: Any] = ["content": content,
                                     "uuid": uuid(),
                                     "platform": platform(),
                                     "app_name": app_name()]
        
        KMAIRequestServer.requestServer.aiRewriting(urlString: urlString, params: params) { formData in
            
        } requestSerializer: { requestSerializer in
            requestSerializer.setValue("Apifox/1.0.0 (https://www.apifox.cn)", forHTTPHeaderField: "User-Agent")
        } completion: { task, responseObject, error in
            if responseObject != nil {
                let data: NSDictionary = responseObject!["data"] as? NSDictionary ?? [:]
                let code: String = responseObject!["code"] as? String ?? "06005"
                let message: String = responseObject!["message"] as? String ?? "unknown error"
                let error = NSError(domain: message, code: Int(code)!)
//                let result = ResultWrapper(success: true, result: data, message: message, code: Int(code)!, error: error, state: state)
//                if result.code == 200 {
//                    result.success = true
//                    complete(result)
//                } else {
//                    result.success = false
//                    complete(result)
//                }
                if Int(code)! == 200 {
                    complete(ResultWrapper(success: true, content: data["content"] as! String))
                } else {
                    complete(ResultWrapper(success: false, content: message))
                }
            } else {
//                let error = NSError(domain: "unknown error", code: 404)
//                let result = ResultWrapper(success: false, result: [:], message: "unknown error", code: 404, error: error, state: state)
//                complete(result)
                complete(ResultWrapper(success: false, content: "unknown error"))
            }
        }
    }
    
    /**
     @abstract 提取摘要
     @param file  文件路径
     */
    private func extractSummaryFile(file: String, complete: @escaping KMRequestServerComplete) {
        
        let infoDictionary = Bundle .main.infoDictionary!
        let urlString = AIInfoConfig().aiActionURL + "/api/AI/extractSummaryFile"
        let fileData = FileManager.default.contents(atPath: file)
        let params: [String: Any] = ["file": fileData,
                                     "uuid": uuid(),
                                     "platform": platform(),
                                     "app_name": app_name()]
        KMAIRequestServer.requestServer.uploadFile(urlString: urlString, params: params) { formData in
            let fileURL = URL(fileURLWithPath: file)
            try? formData.appendPart(withFileURL: fileURL, name: "file", fileName: fileURL.lastPathComponent, mimeType: "application/octet-stream")
        } requestSerializer: { requestSerializer in
            requestSerializer.setValue("Apifox/1.0.0 (https://www.apifox.cn)", forHTTPHeaderField: "User-Agent")
        } completion: { task, responseObject, error in
            if responseObject != nil {
                let data: NSDictionary = responseObject!["data"] as? NSDictionary ?? [:]
                let code: Int = responseObject!["code"] as? Int ?? 06005
                let message: String = responseObject!["message"] as? String ?? "unknown error"
                let error = NSError(domain: message, code: code)
//                let result = ResultWrapper(success: true, result: data, message: message, code: Int(code)!, error: error, state: .extractSummaryFile)
//                if result.code == 200 {
//                    result.success = true
//                    complete(result)
//                } else {
//                    result.success = false
//                    complete(result)
//                }
                if code == 200 {
                    complete(ResultWrapper(success: true, content: data["summary"] as! String))
                } else {
                    complete(ResultWrapper(success: false, content: message))
                }
            } else {
                let error = NSError(domain: "unknown error", code: 404)
//                let result = ResultWrapper(success: false, result: [:], message: "unknown error", code: 404, error: error, state: .extractSummaryFile)
//                complete(result)
                complete(ResultWrapper(success: false, content: "unknown error"))
            }
        }
    }

}

//typealias KMHttpRequestServerComplete = (_ task: URLSessionDataTask?, _ responseObject: AnyObject?, _ error: NSError?) -> Void
class KMAIRequestServer {
    var sessionManager: AFHTTPSessionManager!
    static let requestServer = KMAIRequestServer()
    var task: URLSessionTask?
    
    init() {
        let configuration: URLSessionConfiguration = URLSessionConfiguration.default
        sessionManager = AFHTTPSessionManager.init(sessionConfiguration: configuration)
        sessionManager.securityPolicy = AFSecurityPolicy.default()
    }
    
    /**
     上传文件
        - 翻译
        - 摘要提取
     */
    func uploadFile(urlString: String,
                        params: Dictionary<String, Any>?,
                       body: ((_ formData:AFMultipartFormData) -> Void)?,
          requestSerializer: ((_ requestSerializer:AFHTTPRequestSerializer) -> Void)?,
                     completion: KMHttpRequestServerComplete?) -> Void {
        sessionManager.requestSerializer.setValue("multipart/form-data", forHTTPHeaderField: "Content-Type")
        sessionManager.requestSerializer.timeoutInterval = 60
        sessionManager.responseSerializer = AFJSONResponseSerializer()
        sessionManager.responseSerializer.acceptableContentTypes = ["application/json","text/html","text/json","text/javascript","text/plain","image/gif"]
        if (requestSerializer != nil) {
            requestSerializer!(sessionManager.requestSerializer);
        }
        if (body != nil) {
            self.task = sessionManager.post(urlString, parameters: params, headers: nil) { formData in
                body!(formData)
            } progress: { progress in
                
            } success: { task, responseObject in
                let responseObject = responseObject as AnyObject
                if (completion != nil) {
                    completion!(task,responseObject,nil);
                }
            } failure: { task, error in
                if (completion != nil) {
                    completion!(task, nil, error as NSError);
                }
            }
        } else {
            self.task = sessionManager.post(urlString, parameters: params, headers: nil) { progress in
            
            } success: { task, responseObject in
                if (completion != nil) {
                    let responseObject = responseObject as AnyObject
                    completion!(task,responseObject,nil);
                }
            } failure: { task, error in
                if (completion != nil) {
                    completion!(task, nil, error as NSError);
                }
            }
        }
    }
    
    /**
     文件翻译
     */
    func aiFileTranslateHandle(urlString: String,
                                  params: Dictionary<String, Any>?,
                                    body: ((_ formData:AFMultipartFormData) -> Void)?,
                       requestSerializer: ((_ requestSerializer:AFHTTPRequestSerializer) -> Void)?,
                              completion: KMHttpRequestServerComplete?) -> Void {
        sessionManager.requestSerializer = AFJSONRequestSerializer()
        sessionManager.responseSerializer = AFJSONResponseSerializer()
        sessionManager.responseSerializer.acceptableContentTypes = ["application/json","text/html","text/json","text/javascript","text/plain","image/gif"]
        if (requestSerializer != nil) {
            requestSerializer!(sessionManager.requestSerializer);
        }
        if (body != nil) {
            self.task = sessionManager.post(urlString, parameters: params, headers: nil) { formData in
                body!(formData)
            } progress: { progress in
                
            } success: { task, responseObject in
                let responseObject = responseObject as AnyObject
                if (completion != nil) {
                    completion!(task,responseObject,nil);
                }
            } failure: { task, error in
                if (completion != nil) {
                    completion!(task, nil, error as NSError);
                }
            }
        } else {
            self.task = sessionManager.post(urlString, parameters: params, headers: nil) { progress in
            
            } success: { task, responseObject in
                if (completion != nil) {
                    let responseObject = responseObject as AnyObject
                    completion!(task,responseObject,nil);
                }
            } failure: { task, error in
                if (completion != nil) {
                    completion!(task, nil, error as NSError);
                }
            }
        }
    }
    
    /**
     重写
     */
    func aiRewriting(urlString: String,
                        params: Dictionary<String, Any>?,
                          body: ((_ formData:AFMultipartFormData) -> Void)?,
             requestSerializer: ((_ requestSerializer:AFHTTPRequestSerializer) -> Void)?,
                    completion: KMHttpRequestServerComplete?) -> Void {
        sessionManager.requestSerializer.setValue("multipart/form-data", forHTTPHeaderField: "Content-Type")
        sessionManager.requestSerializer.timeoutInterval = 60
        sessionManager.responseSerializer = AFJSONResponseSerializer()
        sessionManager.responseSerializer.acceptableContentTypes = ["application/json","text/html","text/json","text/javascript","text/plain","image/gif"]
        if (requestSerializer != nil) {
            requestSerializer!(sessionManager.requestSerializer);
        }
        if (body != nil) {
            self.task = sessionManager.post(urlString, parameters: params, headers: nil) { formData in
                body!(formData)
            } progress: { progress in
                
            } success: { task, responseObject in
                let responseObject = responseObject as AnyObject
                if (completion != nil) {
                    completion!(task,responseObject,nil);
                }
            } failure: { task, error in
                if (completion != nil) {
                    completion!(task, nil, error as NSError);
                }
            }
        } else {
            self.task = sessionManager.post(urlString, parameters: params, headers: nil) { progress in
            
            } success: { task, responseObject in
                if (completion != nil) {
                    let responseObject = responseObject as AnyObject
                    completion!(task,responseObject,nil);
                }
            } failure: { task, error in
                if (completion != nil) {
                    completion!(task, nil, error as NSError);
                }
            }
        }
    }
}