//
//  ViewController.swift
//  AltBackup
//
//  Created by Riley Testut on 5/11/20.
//  Copyright © 2020 Riley Testut. All rights reserved.
//

import UIKit

extension Bundle
{
    var appName: String? {
        let appName =
            Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String ??
            Bundle.main.object(forInfoDictionaryKey: kCFBundleNameKey as String) as? String
        return appName
    }
}

extension ViewController
{
    enum BackupOperation
    {
        case backup
        case restore
    }
}

class ViewController: UIViewController
{
    private let backupController = BackupController()
    
    private var currentOperation: BackupOperation? {
        didSet {
            DispatchQueue.main.async {
                self.update()
            }
        }
    }
    
    private var textLabel: UILabel!
    private var detailTextLabel: UILabel!
    private var activityIndicatorView: UIActivityIndicatorView!
    
    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
    
    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?)
    {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        
        NotificationCenter.default.addObserver(self, selector: #selector(ViewController.backup), name: AppDelegate.startBackupNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(ViewController.restore), name: AppDelegate.startRestoreNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(ViewController.didEnterBackground(_:)), name: UIApplication.didEnterBackgroundNotification, object: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError()
    }
    
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        self.view.backgroundColor = .altstoreBackground
        
        self.textLabel = UILabel(frame: .zero)
        self.textLabel.font = UIFont.preferredFont(forTextStyle: .title2)
        self.textLabel.textColor = .altstoreText
        self.textLabel.textAlignment = .center
        self.textLabel.numberOfLines = 0
        
        self.detailTextLabel = UILabel(frame: .zero)
        self.detailTextLabel.font = UIFont.preferredFont(forTextStyle: .body)
        self.detailTextLabel.textColor = .altstoreText
        self.detailTextLabel.textAlignment = .center
        self.detailTextLabel.numberOfLines = 0
        
        self.activityIndicatorView = UIActivityIndicatorView(style: .whiteLarge)
        self.activityIndicatorView.color = .altstoreText
        self.activityIndicatorView.startAnimating()
        
        // TODO: @mahee96: Disabled these backup/restore buttons in altbackup.app screen which were present for debugging purpose.
        //                 Can find something useful for these later, but these are not required by this backup/restore app
//        #if DEBUG
//        let button1 = UIButton(type: .system)
//        button1.setTitle("Backup", for: .normal)
//        button1.setTitleColor(.white, for: .normal)
//        button1.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body)
//        button1.addTarget(self, action: #selector(ViewController.backup), for: .primaryActionTriggered)
//        
//        let button2 = UIButton(type: .system)
//        button2.setTitle("Restore", for: .normal)
//        button2.setTitleColor(.white, for: .normal)
//        button2.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body)
//        button2.addTarget(self, action: #selector(ViewController.restore), for: .primaryActionTriggered)
//        
//        let arrangedSubviews = [self.textLabel!, self.detailTextLabel!, self.activityIndicatorView!, button1, button2]
//        #else
        let arrangedSubviews = [self.textLabel!, self.detailTextLabel!, self.activityIndicatorView!]
//        #endif
        
        let stackView = UIStackView(arrangedSubviews: arrangedSubviews)
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.spacing = 22
        stackView.axis = .vertical
        stackView.alignment = .center
        self.view.addSubview(stackView)
        
        NSLayoutConstraint.activate([stackView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
                                     stackView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),
                                     stackView.leadingAnchor.constraint(greaterThanOrEqualToSystemSpacingAfter: self.view.safeAreaLayoutGuide.leadingAnchor, multiplier: 1.0),
                                     self.view.safeAreaLayoutGuide.trailingAnchor.constraint(greaterThanOrEqualToSystemSpacingAfter: stackView.trailingAnchor, multiplier: 1.0)])
        
        self.update()
    }
}

private extension ViewController
{
    @objc func backup()
    {
        self.currentOperation = .backup
        
        self.backupController.performBackup { (result) in
            let appName = Bundle.main.appName ?? NSLocalizedString("App", comment: "")

            let title = String(format: NSLocalizedString("%@ could not be backed up.", comment: ""), appName)
            self.process(result, errorTitle: title)
        }
    }
    
    @objc func restore()
    {
        self.currentOperation = .restore
        
        self.backupController.restoreBackup { (result) in
            let appName = Bundle.main.appName ?? NSLocalizedString("App", comment: "")

            let title = String(format: NSLocalizedString("%@ could not be restored.", comment: ""), appName)
            self.process(result, errorTitle: title)
        }
    }
    
    func update()
    {
        switch self.currentOperation
        {
        case .backup:
            self.textLabel.text = NSLocalizedString("Backing up app data…", comment: "")
            self.detailTextLabel.isHidden = true
            self.activityIndicatorView.startAnimating()
            
        case .restore:
            self.textLabel.text = NSLocalizedString("Restoring app data…", comment: "")
            self.detailTextLabel.isHidden = true
            self.activityIndicatorView.startAnimating()
        
        // TODO: @mahee96: This is pointless since, app going in bg/fg should still report its last operation properly
        case .none:
            self.textLabel.text = String(format: NSLocalizedString("%@ is inactive.", comment: ""),
                                         Bundle.main.appName ?? NSLocalizedString("App", comment: ""))
                                            
            self.detailTextLabel.text = String(format: NSLocalizedString("Refresh %@ in SideStore to continue using it.", comment: ""),
                                               Bundle.main.appName ?? NSLocalizedString("this app", comment: ""))
            
            self.detailTextLabel.isHidden = false
            self.activityIndicatorView.stopAnimating()
        }
    }
}

private extension ViewController
{
    func process(_ result: Result<Void, Error>, errorTitle: String)
    {
        DispatchQueue.main.async {
            switch result
            {
            case .success: break
            case .failure(let error as NSError):
                let message: String

                if let sourceDescription = error.sourceDescription
                {
                    message = error.localizedDescription + "\n\n" + sourceDescription
                }
                else
                {
                    message = error.localizedDescription
                }

                let alertController = UIAlertController(title: errorTitle, message: message, preferredStyle: .alert)
                alertController.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default, handler: nil))
                self.present(alertController, animated: true, completion: nil)
            }
            
            NotificationCenter.default.post(name: AppDelegate.operationDidFinishNotification, object: nil, userInfo: [AppDelegate.operationResultKey: result])
        }
    }
    
    // TODO: @mahee96: This doesn't account cases where backup is too long and user switched to other apps
    //                 Now the user has lost his progress since current operation was cancelled due to switch between FG and BG
    //                 if this just the reset for enum such that UI stops showing progress circle, then this is fine!
    @objc func didEnterBackground(_ notification: Notification)
    {
        // Reset UI once we've left app (but not before).
        self.currentOperation = nil
    }
}
