import UIKit
import AutoCatCore
import MobileCoreServices
import PKHUD
import RxSwift
import ExceptionCatcher
import RealmSwift

class NotesController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    
    @IBOutlet weak var notesTable: UITableView!
    
    private var textView = UITextView()
    private var bag = DisposeBag()

    var vehicle: Vehicle? {
        didSet {
            if self.isViewLoaded {
                self.notesTable.reloadData()
            }
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()

        self.title = NSLocalizedString("Notes", comment: "")
        self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addNote(_:)))
        self.notesTable.reloadData()
        self.hideKeyboardWhenTappedAround()
    }
    
    @discardableResult
    func update(vehicle: Vehicle) -> Bool {
        do {
            if let v = self.vehicle, let realm = v.realm, !v.isFrozen {
                try ExceptionCatcher.catch {
                    try realm.write {
                        realm.add(vehicle, update: .all)
                    }
                }
            } else {
                self.vehicle?.notes.removeAll()
                self.vehicle?.notes.append(objectsIn: vehicle.notes)
            }
            self.notesTable.reloadData()
            return true
        } catch {
            self.show(error: error)
            return false
        }
    }
    
    // MARK: - UITableViewDataSource
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.vehicle?.notes.count ?? 0
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "VehicleNoteCell", for: indexPath) as? VehicleNoteCell else {
            return UITableViewCell()
        }
        
        if let note = self.vehicle?.notes[indexPath.row] {
            cell.configure(with: note)
        }

        return cell
    }
    
    // MARK: - UITableViewDelegate
    
    func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
        return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ in
            let copy = UIAction(title: NSLocalizedString("Copy", comment: ""), image: UIImage(systemName: "doc.on.doc")) { action in
                self.copyNote(index: indexPath.row)
            }
            
            let edit = UIAction(title: NSLocalizedString("Edit", comment: ""), image: UIImage(systemName: "pencil")) { action in
                self.editNote(index: indexPath.row)
            }
            
            let delete = UIAction(title: NSLocalizedString("Delete", comment: ""), image: UIImage(systemName: "trash"), attributes: .destructive) { action in
                self.deleteNote(index: indexPath.row)
            }

            return UIMenu(title: NSLocalizedString("Actions", comment: ""), children: [copy, edit, delete])
        }
    }
    
    func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        let copy = UIContextualAction(style: .normal, title: NSLocalizedString("Copy", comment: "")) { action, view, completion in
            self.copyNote(index: indexPath.row)
            completion(true)
        }
        copy.image = UIImage(systemName: "doc.on.doc")
        copy.backgroundColor = .systemBlue
        
        let delete = UIContextualAction(style: .destructive, title: NSLocalizedString("Delete", comment: "")) { action, view, completion in
            self.deleteNote(index: indexPath.row, completion: completion)
        }
        delete.image = UIImage(systemName: "trash")
        
        let edit = UIContextualAction(style: .normal, title: NSLocalizedString("Edit", comment: "")) { action, view, completion in
            self.editNote(index: indexPath.row)
            completion(true)
        }
        edit.image = UIImage(systemName: "pencil")
        edit.backgroundColor = .systemBlue
        
        let configuration = UISwipeActionsConfiguration(actions: [delete, edit, copy])
        configuration.performsFirstActionWithFullSwipe = false
        return configuration
    }
    
    // MARK: - Actions
    
    @objc func addNote(_ sender: UIBarButtonItem) {
        guard let vehicle = self.vehicle else {
            HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle"))
            return
        }
        
        self.showAddNoteAlert(text: nil) { noteText in
            let note = VehicleNote(text: noteText)
            
            if vehicle.unrecognized {
                if let realm = vehicle.realm {
                    try? realm.write {
                        vehicle.notes.append(note)
                        vehicle.updatedDate = Date().timeIntervalSince1970
                    }
                    self.notesTable.reloadData()
                }
                return
            }
            
            HUD.show(.progress)
            Api.add(notes: [note], to: vehicle.getNumber())
                .observeOn(MainScheduler.instance)
                .subscribe(onSuccess: {
                    HUD.hide()
                    self.update(vehicle: $0)
                }, onError: { error in
                    HUD.hide()
                    self.show(error: error)
                })
                .disposed(by: self.bag)
        }
    }
    
    func copyNote(index: Int) {
        guard let vehicle = self.vehicle else {
            HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle"))
            return
        }
        
        UIPasteboard.general.setValue(vehicle.notes[index].text, forPasteboardType: kUTTypePlainText as String)
    }
    
    func editNote(index: Int) {
        guard let vehicle = self.vehicle else {
            HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle"))
            return
        }
        
        let note = vehicle.notes[index]
        self.showAddNoteAlert(text: note.text) { noteText in
            
            if vehicle.unrecognized {
                if let realm = vehicle.realm {
                    try? realm.write {
                        note.text = noteText
                        vehicle.updatedDate = Date().timeIntervalSince1970
                    }
                    self.notesTable.reloadData()
                }
                return
            }
            
            HUD.show(.progress)
            let newNote = note.clone()
            newNote.text = noteText
            Api.edit(note: newNote)
                .observeOn(MainScheduler.instance)
                .subscribe(onSuccess: {
                    HUD.hide()
                    self.update(vehicle: $0)
                }, onError: { error in
                    HUD.hide()
                    self.show(error: error)
                })
                .disposed(by: self.bag)
        }
    }
    
    func deleteNote(index: Int, completion: ((Bool) -> Void)? = nil) {
        guard let vehicle = self.vehicle else {
            HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle"))
            return
        }
        
        let note = vehicle.notes[index]
        
        if vehicle.unrecognized {
            if let realm = vehicle.realm {
                try? realm.write {
                    vehicle.notes.remove(at: index)
                    vehicle.updatedDate = Date().timeIntervalSince1970
                    realm.delete(note)
                }
                self.notesTable.reloadData()
            }
            return
        }
        
        HUD.show(.progress)
        Api.remove(note: note.id)
            .observeOn(MainScheduler.instance)
            .subscribe(onSuccess: { vehicle in
                HUD.hide()
                let result = self.update(vehicle: vehicle)
                completion?(result)
            }, onError: { error in
                completion?(false)
                HUD.hide()
                self.show(error: error)
                print(error)
            }).disposed(by: self.bag)
    }
    
    // MARK: - Utils
    
    func showAddNoteAlert(text: String?, completion: @escaping (String) -> Void) {
        let alertController = UIAlertController(title: NSLocalizedString("New note", comment: ""), message: nil, preferredStyle: .alert)

        let cancelAction = UIAlertAction.init(title:  NSLocalizedString("Cancel", comment: ""), style: .default)
        alertController.addAction(cancelAction)

        let saveAction = UIAlertAction(title:  NSLocalizedString("Done", comment: ""), style: .default) { (action) in
            let enteredText = self.textView.text ?? ""
            completion(enteredText)
        }
        alertController.addAction(saveAction)
        self.textView = UITextView()
        self.textView.text = text
        self.textView.addDoneButton(title: NSLocalizedString("Done", comment: ""), target: self, selector: #selector(tapDone(sender:)))
        self.textView.translatesAutoresizingMaskIntoConstraints = false
        alertController.view.addSubview(self.textView)
        
        NSLayoutConstraint.activate([
            self.textView.topAnchor.constraint(equalTo: alertController.view.topAnchor, constant: 60),
            self.textView.bottomAnchor.constraint(equalTo: alertController.view.bottomAnchor, constant: -60),
            self.textView.leadingAnchor.constraint(equalTo: alertController.view.leadingAnchor, constant: 8),
            self.textView.trailingAnchor.constraint(equalTo: alertController.view.trailingAnchor, constant: -8),
            self.textView.heightAnchor.constraint(greaterThanOrEqualToConstant: 100)
        ])

        self.present(alertController, animated: true) {
            self.textView.becomeFirstResponder()
        }
    }
    
    @objc func tapDone(sender: Any) {
        self.textView.endEditing(true)
    }
}
