//
//  KMUserFeekbackWindowController.swift
//  PDF Reader Pro Edition
//
//  Created by tangchao on 2024/7/11.
//

import Cocoa

@objcMembers class KMUserFeekbackWindowController: NSWindowController {
    static let shared = KMUserFeekbackWindowController(windowNibName: "KMUserFeekbackWindowController")

    @IBOutlet weak var emailBox: NSBox!
    @IBOutlet weak var typeBox: NSBox!
    @IBOutlet weak var despBox: NSBox!
    @IBOutlet weak var listHeaderBox: NSBox!
    @IBOutlet weak var listBox: NSBox!
    @IBOutlet weak var comfirmButton: NSButton!
    @IBOutlet weak var cancelButton: NSButton!
    
    private var emailItemView_: KMUserFbEmailItemView?
    private var typeItemView_: KMUserFbTypeItemView?
    private var despItemView_: KMUserFbDespItemView?
    private var listHeaderItemView_: KMUserFbListHeaderItemView?
    private var listItemView_: KMUserListItemView?
    
    typealias KMRequestServerComplete = (_ wrapper: ResultWrapper) -> Void
    
    private var filePaths_: [String] = []
    
    private var logPath_: String?
    
    private var popover_: NSPopover?
    
    var typeString: String = ""
    
    @IBOutlet weak var listHeaderItemHConst: NSLayoutConstraint!
    
    private var fileFormats_: [String] = ["jpg", "jpeg", "png", "gif", "bmp", "tiff", "tif", "psd", "svg", "pdf", "mp4", "mov", "avi", "mkv", "wmv", "flv", "mpg", "3gp", "doc", "docx", "xls" ,"xlsx", "ppt", "pptx", "txt", "rtf", "nfo"]
    private var fileFormatsString = "jpg, jpeg, png, gif, bmp, tiff, tif, psd, svg, pdf, mp4, mov, avi, mkv, wmv, flv, mpg, 3gp, doc, docx, xls,xlsx, ppt, pptx, txt, rtf, nfo"
    
    deinit {
        Swift.debugPrint("KMUserFeekbackWindowController deinit.")
        
        DistributedNotificationCenter.default().removeObserver(self)
    }
    
    override func windowDidLoad() {
        super.windowDidLoad()

        self._initDefaultValue()
        self._initSubViews()
        
        self.typeItemView_?.comBoBox.selectItem(at: 0)
        
        self.updateViewColor()
        DistributedNotificationCenter.default().addObserver(self, selector: #selector(themeChanged), name: NSApplication.interfaceThemeChangedNotification, object: nil)
    }
    
    private func _initDefaultValue() {
        if let btn = self.window?.standardWindowButton(.miniaturizeButton) {
            btn.isHidden = true
        }
        if let btn = self.window?.standardWindowButton(.zoomButton) {
            btn.isHidden = true
        }
        self.window?.title = NSLocalizedString("Feedback for PDF Reader Pro", comment: "")
        
        self.emailBox.borderWidth = 0
        self.typeBox.borderWidth = 0
        self.despBox.borderWidth = 0
        self.listHeaderBox.borderWidth = 0
        self.listBox.borderWidth = 0
        
#if !VERSION_DMG
        self.listHeaderItemHConst.constant = 44
#endif
        
        let email = VerificationManager.default()?.email ?? ""
        self.emailItemView_?.textfiled.stringValue = email
        
        self.emailItemView_?.textfiled.nextResponder = self.despItemView_?.textView
        
        self.cancelButton.title = NSLocalizedString("Cancel", comment: "")
        self.comfirmButton.title = NSLocalizedString("Submit", comment: "")
        
        self.cancelButton.target = self
        self.cancelButton.action = #selector(_cancelButtonAction)
        self.comfirmButton.target = self
        self.comfirmButton.action = #selector(_comfirmButtonAction)
    }
    
    private func _initSubViews() {
        self.emailItemView_ = KMUserFbEmailItemView.createFromNib()
        self.emailBox.contentView = self.emailItemView_
        
        self.typeItemView_ = KMUserFbTypeItemView.createFromNib()
        self.typeBox.contentView = self.typeItemView_
        
        self.despItemView_ = KMUserFbDespItemView.createFromNib()
        self.despBox.contentView = self.despItemView_
        
        self.listHeaderItemView_ = KMUserFbListHeaderItemView.createFromNib()
        self.listHeaderBox.contentView = self.listHeaderItemView_
        
        self.listItemView_ = KMUserListItemView.createFromNib()
        self.listBox.contentView = self.listItemView_
        
        self.listItemView_?.hiddenTip()
        
        self.listHeaderItemView_?.helpHoverCallback = { [weak self] action in
            if action.rawValue == 0 { // enter
                self?._showHelpPopover((self?.listHeaderItemView_?.helpButton)!)
            } else if action.rawValue == 2 { // exit
                self?._hiddenHelpPopover()
            }
        }
        self.listHeaderItemView_?.itemClick = { [weak self] idx in
            if idx == 1 { // 获取日志文件
                
            } else if idx == 3 { // 新增文件
                let panel = NSOpenPanel()
//                panel.message = self?.fileFormatsString
                panel.allowedFileTypes = self?.fileFormats_
                panel.allowsMultipleSelection = true
                panel.beginSheetModal(for: self!.window!) { resp in
                    if resp == .cancel {
                        return
                    }
                    
                    for url in panel.urls {
                        self?.filePaths_.append(url.path)
                    }
                    
                    self?._updateListData()
                }
            }
        }
        
        self.listItemView_?.itemClick = { [weak self] idx, param in
            if let cnt = self?.filePaths_.count, idx < cnt {
                self?.filePaths_.remove(at: idx)
                
                self?._updateListData()
            }
        }
        
        self.listItemView_?.validateDropCallback = { [weak self] info, row, dropOperation in
            let datas = self?.filePaths_.count ?? 0
            if datas >= 10 {
                return NSDragOperation(rawValue: 0)
            }
            return .generic
        }
        
        self.listItemView_?.acceptDropCallback = { [weak self] info, row, dropOperation in 
            let pborad = info.draggingPasteboard
            guard let _ = pborad.availableType(from: [.fileURL]) else {
                return false
            }
            guard let items = pborad.pasteboardItems else {
                return false
            }
            for item in items {
                let string = item.propertyList(forType: .fileURL) as? String ?? ""
                if let path = URL(string: string)?.path {
                    let contains = self?._fileFormatIsContains(URL(string: string)!.pathExtension) ?? false
                    if contains {
                        self?.filePaths_.append(path)
                    }
                }
            }
            self?._updateListData()
            return true
        }
    }
    
    override func showWindow(_ sender: Any?) {
        super.showWindow(sender)
        
        self.typeItemView_?.comBoBox.stringValue = self.typeString
    }
    
    func updateViewColor() {
        if KMAppearance.isDarkMode() {
            self.window?.backgroundColor = NSColor(red: 40/255.0, green: 40/255.0, blue: 40/255.0, alpha: 1)
            self.emailItemView_?.box.fillColor = NSColor(red: 110/255.0, green: 109/255.0, blue: 112/255.0, alpha: 1)
            self.typeItemView_?.comBoBox.backgroundColor = NSColor(red: 110/255.0, green: 109/255.0, blue: 112/255.0, alpha: 1)
            self.despItemView_?.box.fillColor = NSColor(red: 110/255.0, green: 109/255.0, blue: 112/255.0, alpha: 1)
            self.listItemView_?.tipBox.fillColor = NSColor(red: 231/255.0, green: 56/255.0, blue: 91/255.0, alpha: 1)
        } else {
            self.window?.backgroundColor = .white
            self.emailItemView_?.box.fillColor = .white
            self.typeItemView_?.comBoBox.backgroundColor = .white
            self.despItemView_?.box.fillColor = .white
            self.listItemView_?.tipBox.fillColor = NSColor.km_init(hex: "#FEE4EC")
        }
    }
    
    // MARK: - Noti Methods
    
    @objc func themeChanged(_ notification: Notification) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
            self.updateViewColor()
        }
    }
    
    // MARK: - Private Methods
    
    @objc private func _cancelButtonAction() {
        self.window?.orderOut(nil)
    }
    
    @objc private func _comfirmButtonAction() {
#if VERSION_DMG
        if let data = self.listHeaderItemView_?.checkButton.state, data == .on {
            let fileaccess = AppSandboxFileAccess()
            // /Users/kdanmobile/Library/Logs/DiagnosticReports
            let url = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first
            let coms = url?.pathComponents ?? []
            var filePath: String = ""
            for (i, com) in coms.enumerated() {
                if i > 2 {
                    break
                } else {
                    filePath.append("/\(com)")
                }
            }
            let cmd = filePath.appending("/Library/Logs/DiagnosticReports/")
            // /Library/Logs/DiagnosticReports/
//            fileaccess?.accessFilePath(cmd, persistPermission: true, with: {
//
//            })
            
            let logString = self._getLog()
            if logString.isEmpty == false {
                let bundleIdentifier = Bundle.main.bundleIdentifier ?? "PDF Reader Pro"
                if let url = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first?.appendingPathComponent(bundleIdentifier) {
                    if FileManager.default.fileExists(atPath: url.path) == false {
                        try?FileManager.default.createDirectory(at: url, withIntermediateDirectories: false)
                    }
                    
                    let fileUrl = url.appendingPathComponent("Log.txt")
                    
                    try?logString.write(to: fileUrl, atomically: true, encoding: .utf8)
                    
                    self.logPath_ = fileUrl.path
                }
            }
        } else {
            self.logPath_ = nil
        }
#endif
        
        self.window?.makeFirstResponder(nil)
        let state = self._isConnectionAvailable()
        if !state {
            self._showHud(msg: NSLocalizedString("Please make sure your internet connection is available.", comment: ""))
            return
        }
        
        guard let emailString = self.emailItemView_?.string(), emailString.isEmpty == false else {
            // 邮箱为空
            self.emailItemView_?.showTip(label: NSLocalizedString("Please enter your email", comment: ""))
            return
        }
        
        if KMValidateEmail(email: emailString) == false {
            self.emailItemView_?.showTip(label: NSLocalizedString("Please enter valid email", comment: ""))
            return
        }
        
        guard let despString = self.despItemView_?.string(), despString.isEmpty == false else {
            // 描述信息为空
            self.despItemView_?.showTip()
            return
        }
        
        self.window?.contentView?.beginLoading()
        self.comfirmButton.isEnabled = false
        var filePaths: [String] = self.filePaths_
#if VERSION_DMG
        if let data = self.listHeaderItemView_?.checkButton.state, data == .on {
            if let filePath = self.logPath_, filePath.isEmpty == false {
                filePaths.append(filePath)
            }
        }
#endif
        
        self._feekbackAction(filePaths: filePaths) { [weak self] wrapper in
            self?.window?.contentView?.endLoading()
            self?.comfirmButton.isEnabled = true
            if wrapper.success {
                self?._showHud(msg: NSLocalizedString("Thank you for your feedback! Customer service will feedback to your email within 1 working day", comment: ""))
                
                DispatchQueue.main.asyncAfter(deadline: .now() + 1.8) {
                    self?.despItemView_?.textView.string = ""
                    self?.despItemView_?.textView.placeholderLabel.isHidden = false;
                    self?.filePaths_.removeAll()
                    self?._updateListData()
                    
                    if let data = self?.logPath_, data.isEmpty == false {
                        if FileManager.default.fileExists(atPath: data) {
                            try?FileManager.default.removeItem(atPath: data)
                        }
                    }
                    
                    self?.logPath_ = nil
                    self?.window?.orderOut(nil)
                }
            } else {
                self?._showHud(msg: wrapper.content)
            }
        }
    }
    
    private func _showHelpPopover(_ sender: NSButton) {
        if self.popover_ != nil {
            return
        }
        let vc = KMUserFbHelpPopController()
        vc.formatSting = self.fileFormatsString
        let popover = NSPopover()
        popover.contentViewController = vc
        popover.animates = true
        popover.behavior = .semitransient
        popover.delegate = self
        popover.setValue(true, forKey: "shouldHideAnchor")
        self.popover_ = popover
        
        vc.isDrak = KMAppearance.isDarkMode()
        
        popover.show(relativeTo: sender.bounds, of: sender, preferredEdge: .maxX)
    }
    
    private func _hiddenHelpPopover() {
        self.popover_?.close()
    }
    
    private func _updateListData() {
        self.listItemView_?.hiddenTip()
        
        var datas: [KMUserFbListModel] = []
        let maxSize: Double = 20 * 1024 * 1024
        var fileSize: Double = 0
        var filePaths: [String] = []
        var showFileSizeLimit = false
        var showFileCountLimit = false
        for (i, fileP) in self.filePaths_.enumerated() {
            let model = KMUserFbListModel()
            model.filePath = fileP
            let url = URL(fileURLWithPath: fileP)
            model.fileName = url.lastPathComponent
            let attri = try?FileManager.default.attributesOfItem(atPath: fileP)
            model.fileSize = attri?[FileAttributeKey.size] as? Double ?? 0
            
//            fileSize += model.fileSize
            fileSize = model.fileSize
            if fileSize >= maxSize {
                showFileSizeLimit = true
                continue
            }
            if i >= 10 {
                showFileCountLimit = true
                break
            }
            
            model.fileSizeString = self.fileSizeString(model.fileSize) ?? ""
            datas.append(model)
            
            filePaths.append(fileP)
        }
        self.filePaths_ = filePaths
        
        if showFileCountLimit {
            self.listItemView_?.showTip(tip: NSLocalizedString("Add failed: upload up to 10 files", comment: ""))
        } else if showFileSizeLimit {
            self.listItemView_?.showTip(tip: NSLocalizedString("Add failed: attachment size cannot exceed 20M", comment: ""))
        }
        
        if datas.count >= 10 {
            self.listHeaderItemView_?.addButton.isEnabled = false
        } else {
            self.listHeaderItemView_?.addButton.isEnabled = true
        }
        
        self.listItemView_?.datas = datas
    }
    
    private func _showHud(msg: String) {
        if let data = self.window?.contentView {
//            _ = CustomAlertView(message: msg, from: data, with: .black)
            CustomAlertView.alertView(message: msg, fromView: data, withStyle: .black)
        }
    }
    
#if VERSION_DMG
    private func _getLog() -> String {
        let url = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first
        let coms = url?.pathComponents ?? []
        var filePath: String = ""
        for (i, com) in coms.enumerated() {
            if i > 2 {
                break
            } else {
                filePath.append("/\(com)")
            }
        }
        // ls /Library/Logs/DiagnosticReports/PDF*
        let cmd = "ls \(filePath)/Library/Logs/DiagnosticReports/PDF*"
        let filestrings = _runShellCommand(cmd)
        let files = filestrings.components(separatedBy: "\n")
        var results: [String] = []
        for string in files {
            if string.contains("PDF Reader Pro") {
                var tempS = string
//                tempS.replace(" ", with: "\\ ")
//                tempS.replacingCharacters(in: " ", with: "\\ ")
//                let ss = tempS.replacing(" ", with: "\\ ")
                let ss = tempS.replacingOccurrences(of: " ", with: "\\ ")
                results.append(ss)
            }
        }
        
        if results.isEmpty {
            let cmd = "ls \(filePath)/Library/Logs/DiagnosticReports/Retired/PDF*"
            let filestrings = _runShellCommand(cmd)
            let files = filestrings.components(separatedBy: "\n")
            for string in files {
                if string.contains("PDF Reader Pro") {
                    var tempS = string
    //                tempS.replace(" ", with: "\\ ")
    //                tempS.replacingCharacters(in: " ", with: "\\ ")
    //                let ss = tempS.replacing(" ", with: "\\ ")
                    let ss = tempS.replacingOccurrences(of: " ", with: "\\ ")
                    results.append(ss)
                }
            }
        }
        
        if let file = results.last {
            let cmd = "cat \(file)"
            // cat /Library/Logs/DiagnosticReports/PDF*
            let logs = _runShellCommand(cmd)
            return logs
        }
        return ""
    }
#endif
    
    private func _runShellCommand(_ command: String) -> String {
        let task = Process()
        let pipe = Pipe()
        
        task.standardOutput = pipe
        task.standardError = pipe
        task.arguments = ["-c", command]
        task.launchPath = "/bin/bash"
        
        do {
            try task.run()
        } catch {
            return "Error running command: \(error)"
        }
        
        let data = pipe.fileHandleForReading.readDataToEndOfFile()
        let output = String(data: data, encoding: .utf8) ?? ""
        return output
    }
    
    func test() {
        var convertString = "TARGET_BUNDLE_IDENTIFIER=\"com.brother.pdfreaderprofree.mac\"\n"
        convertString = convertString.appendingFormat("SANDBOX_ROOT=$(osascript -e 'tell application \"System Events\" to get the path of the home folder of (system info)')\n")
        convertString = convertString.appendingFormat("CONTAINER_LOG_PATH=$(osascript <<EOF\n")
        convertString.append("tell application \"System Events\"\n")
//        convertString.append("set isRun to running\n")
        convertString.append("set container_path to POSIX path of (the home folder as text) & \"Library:Containers:\" & \"$TARGET_BUNDLE_IDENTIFIER\"\n")
        convertString.append("set log_path to container_path & \":Logs:\" & \"Console.app-History\"\n")
        convertString.append("return log_path\n")
        convertString.append("end tell\n")
        convertString.append("EOF)\n")
        
        convertString.append("echo \"日志文件路径: $CONTAINER_LOG_PATH\"\n")

        var dic: NSDictionary?
        let docScript = NSAppleScript(source: convertString)
        docScript?.executeAndReturnError(&dic)
    }
    
    func fileSizeString(_ fSize: Double) -> String {
        let fileSize = fSize / 1024
        let size = fileSize >= 1024 ? (fileSize < 1048576 ? fileSize/1024 : fileSize/1048576.0) : fileSize
        let unit = fileSize >= 1024 ? (fileSize < 1048576 ? "M" : "G") : "K"
        return String(format: "%0.1f %@", size, unit)
    }
    
    private func _feekbackAction(filePaths: [String], complete: @escaping KMRequestServerComplete) {
        let urlString = kVerificationServer + "/api/feedback/feedback"
        var fileDatas: [Data] = []
        for filePath in filePaths {
            if let fileData = FileManager.default.contents(atPath: filePath) {
                fileDatas.append(fileData)
            }
        }
        let (major, minor, bugFix) = KMTools.getSystemVersion()
        let versionInfoString = "\(KMTools.getRawSystemInfo()) - \(major).\(minor).\(bugFix)"
        
        let appVersion = KMTools.getAppVersion()
        let appName = KMTools.getAppNameForSupportEmail()
        
        let typeString = (self.typeItemView_?.string() ?? "") + ";" + appName + " - " + appVersion + ";" + versionInfoString
        let uuid = GetHardwareUUID()
        let params: [String: Any] = ["email": self.emailItemView_?.string() ?? "",
                                     "title": typeString,
                                     "content": self.despItemView_?.string() ?? "",
                                     "unique_sn" : uuid!,
                                     "files[]" : fileDatas]
        KMAIRequestServer.requestServer.uploadFile(urlString: urlString, params: params) { formData in
            for i in 0 ..< fileDatas.count {
                let path = filePaths[i]
                let fileURL = URL(fileURLWithPath: path)
                try? formData.appendPart(withFileURL: fileURL, name: "files[]", 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 as? NSDictionary ?? [:]
//                var code: String = responseObject!["code"] as? String ?? "06005"
                let code = data["code"] as? Int ?? 06005
                if code == 06005 {
//                    let tempCode: Int = responseObject!["code"] as? Int ?? 0
//                    if tempCode == 501 {
//                        code = "501"
//                    }
                }
                
                let message: String = data["message"] as? String ?? "unknown error"
                let error = NSError(domain: message, code: code)
                if 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 code == 501 {
                        wrapper.content = "501"
                    } else {
                        wrapper.content = message
                    }
                    complete(wrapper)
                }
            } else {
                complete(ResultWrapper(success: false, content: "unknown error"))
            }
        }
    }
    
    private func _isConnectionAvailable() -> Bool {
        if Reachability.forInternetConnection().currentReachabilityStatus().rawValue == 0 {
            return false
        }
        return true
    }
    
    private func _fileFormatIsContains(_ exn: String) -> Bool {
        let _exn = exn.lowercased()
        return self.fileFormats_.contains(_exn)
    }
    
}

extension KMUserFeekbackWindowController: NSPopoverDelegate {
    func popoverWillClose(_ notification: Notification) {
        if let data = self.popover_?.isEqual(to: notification.object), data {
            self.popover_ = nil
        }
    }
}