//
//  IssueReporterViewController.swift
//  Tusker
//
//  Created by Shadowfacts on 6/20/20.
//  Copyright © 2020 Shadowfacts. All rights reserved.
//

import UIKit
import MessageUI
import OSLog

class IssueReporterViewController: UIViewController {
    
    static func create(_ self: IssueReporterViewController) -> UINavigationController {
        let nav = UINavigationController(rootViewController: self)
        nav.navigationBar.prefersLargeTitles = true
        return nav
    }
    
    static func create(reportText: String, reportFilename: String? = nil, dismiss: @escaping () -> Void) -> UINavigationController {
        let filename = reportFilename ?? "Tusker-error-\(ISO8601DateFormatter().string(from: Date())).txt"
        return create(IssueReporterViewController(reportText: reportText, reportFilename: filename, dismiss: dismiss))
    }
    
    let reportText: String
    let reportFilename: String
    private let doDismiss: () -> Void
    
    var preamble: String {
        "Tusker has encountered an error. You can email a report to the developer. You may review the report below before sending.\n\nIf you choose to send the report, please include any additional details about what you were doing prior that may be pertinent."
    }
    var subject: String {
        "Tusker Error Report"
    }
    
    private let logDataTask: Task<Data?, Never>
    
    @IBOutlet weak var crashReportTextView: UITextView!
    @IBOutlet weak var sendReportButton: UIButton!
    
    init(reportText: String, reportFilename: String, dismiss: @escaping () -> Void) {
        self.reportText = reportText
        self.reportFilename = reportFilename
        self.doDismiss = dismiss
        
        self.logDataTask = Task(priority: .userInitiated) {
            return await withCheckedContinuation({ continuation in
                DispatchQueue.global().async {
                    continuation.resume(returning: Logging.getLogData())
                }
            })
        }
        
        super.init(nibName: "IssueReporterViewController", bundle: .main)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        
        navigationItem.title = "Report an Error"
        navigationItem.largeTitleDisplayMode = .always
        
        crashReportTextView.font = .monospacedSystemFont(ofSize: 14, weight: .regular)
        
        let attributed = NSMutableAttributedString()
        attributed.append(NSAttributedString(string: preamble, attributes: [
            NSAttributedString.Key.font: UIFont.systemFont(ofSize: 17),
            NSAttributedString.Key.foregroundColor: UIColor.label
        ]))
        attributed.append(NSAttributedString(string: "\n\n"))
        attributed.append(NSAttributedString(string: reportText, attributes: [
            NSAttributedString.Key.font: UIFont.monospacedSystemFont(ofSize: 14, weight: .regular),
            NSAttributedString.Key.foregroundColor: UIColor.label
        ]))
        crashReportTextView.attributedText = attributed
        
        sendReportButton.layer.cornerRadius = 12.5
        sendReportButton.layer.masksToBounds = true
        
        sendReportButton.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: #selector(sendReportButtonLongPressed)))
    }
    
    private func updateSendReportButtonColor(lightened: Bool, animate: Bool) {
        let color: UIColor
        if lightened {
            var hue: CGFloat = 0, saturation: CGFloat = 0, brightness: CGFloat = 0, alpha: CGFloat = 0
            UIColor.systemBlue.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha)
            color = UIColor(hue: hue, saturation: 0.85 * saturation, brightness: brightness, alpha: alpha)
        } else {
            color = .systemBlue
        }
        if animate {
            UIView.animate(withDuration: 0.25) {
                self.sendReportButton.backgroundColor = color
            }
        } else {
            sendReportButton.backgroundColor = color
        }
    }
    
    @IBAction func sendReportTouchDown(_ sender: Any) {
        updateSendReportButtonColor(lightened: true, animate: false)
    }
    
    @IBAction func sendReportButtonTouchDragExit(_ sender: Any) {
        updateSendReportButtonColor(lightened: false, animate: true)
    }
    
    @IBAction func sendReportButtonTouchDragEnter(_ sender: Any) {
        updateSendReportButtonColor(lightened: true, animate: true)
    }
    
    @IBAction func sendReportTouchUpInside(_ sender: Any) {
        updateSendReportButtonColor(lightened: false, animate: true)
        sendReportButton.isEnabled = false
        
        Task {
            let composeVC = MFMailComposeViewController()
            composeVC.mailComposeDelegate = self
            composeVC.setToRecipients(["hello@vaccor.space"])
            composeVC.setSubject(subject)
            
            let data = reportText.data(using: .utf8)!
            composeVC.addAttachmentData(data, mimeType: "text/plain", fileName: reportFilename)
            
            if let (logData, name) = await getLogData() {
                composeVC.addAttachmentData(logData, mimeType: "text/plain", fileName: name)
            }
            
            self.present(composeVC, animated: true)
            
            sendReportButton.isEnabled = true
        }
    }
    
    @objc func sendReportButtonLongPressed() {
        let dir = FileManager.default.temporaryDirectory
        let url = dir.appendingPathComponent(reportFilename)
        try! reportText.data(using: .utf8)!.write(to: url)
        let activityController = UIActivityViewController(activityItems: [url], applicationActivities: nil)
        activityController.popoverPresentationController?.sourceView = sendReportButton
        present(activityController, animated: true)
    }

    @IBAction func cancelPressed(_ sender: Any) {
        self.finishedReport()
        doDismiss()
    }
    
    func getLogData() async -> (Data, String)? {
        guard let data = await logDataTask.value else {
            return nil
        }
        let timestamp = ISO8601DateFormatter().string(from: Date())
        return (data, "Tusker-\(timestamp).log")
    }
    
    func finishedReport() {
    }

}

extension IssueReporterViewController: MFMailComposeViewControllerDelegate {
    func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
        controller.dismiss(animated: true) {
            if result == .cancelled {
                // don't dismiss ourself, to allowe the user to send the report a different way
            } else {
                self.finishedReport()
                self.doDismiss()
            }
        }
    }
}
