//
//  ComposeDrawingViewController.swift
//  Tusker
//
//  Created by Shadowfacts on 5/7/20.
//  Copyright © 2020 Shadowfacts. All rights reserved.
//

import UIKit
import PencilKit

protocol ComposeDrawingViewControllerDelegate: AnyObject {
    func composeDrawingViewControllerClose(_ drawingController: ComposeDrawingViewController)
    func composeDrawingViewController(_ drawingController: ComposeDrawingViewController, saveDrawing drawing: PKDrawing)
}

class ComposeDrawingNavigationController: UINavigationController {
    override var preferredStatusBarStyle: UIStatusBarStyle {
        .darkContent
    }
    
    init(editing initialDrawing: PKDrawing, delegate: ComposeDrawingViewControllerDelegate) {
        let vc = ComposeDrawingViewController(editing: initialDrawing)
        vc.delegate = delegate
        super.init(rootViewController: vc)
        
        modalPresentationStyle = .fullScreen
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        overrideUserInterfaceStyle = .light
    }
}

class ComposeDrawingViewController: UIViewController {
    
    weak var delegate: ComposeDrawingViewControllerDelegate?
    
    private(set) var canvasView: PKCanvasView!
    private(set) var cancelBarButtonItem: UIBarButtonItem!
    private(set) var undoBarButtonItem: UIBarButtonItem!
    private(set) var redoBarButtonItem: UIBarButtonItem!
    
    private var toolPicker: PKToolPicker!
    
    private var initialDrawing: PKDrawing?
    
    init() {
        super.init(nibName: nil, bundle: nil)
    }
    
    convenience init(editing initialDrawing: PKDrawing) {
        self.init()
        
        self.initialDrawing = initialDrawing
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        
        overrideUserInterfaceStyle = .light
        
        navigationItem.title = NSLocalizedString("Draw", comment: "compose drawing screen title")
        cancelBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelPressed))
        undoBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "arrow.uturn.left.circle"), style: .plain, target: self, action: #selector(undoPressed))
        undoBarButtonItem.isEnabled = false
        redoBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "arrow.uturn.right.circle"), style: .plain, target: self, action: #selector(redoPressed))
        redoBarButtonItem.isEnabled = false
        navigationItem.leftBarButtonItems = [cancelBarButtonItem]
        navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(savePressed))
        
        canvasView = PKCanvasView()
        if let initialDrawing = initialDrawing {
            canvasView.drawing = initialDrawing
        }
        canvasView.delegate = self
        canvasView.drawingPolicy = .anyInput
        canvasView.minimumZoomScale = 0.5
        canvasView.maximumZoomScale = 2
        canvasView.backgroundColor = .white
        canvasView.overrideUserInterfaceStyle = .light
        canvasView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(canvasView)
        NSLayoutConstraint.activate([
            canvasView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            canvasView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            canvasView.topAnchor.constraint(equalTo: view.topAnchor),
            canvasView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
        
        toolPicker = PKToolPicker()
        toolPicker.overrideUserInterfaceStyle = .light
        toolPicker.setVisible(true, forFirstResponder: canvasView)
        toolPicker.addObserver(canvasView)
        toolPicker.addObserver(self)
        
        updateLayout(for: toolPicker)
        canvasView.becomeFirstResponder()
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        NotificationCenter.default.addObserver(self, selector: #selector(self.updateUndoRedoButtonState), name: .NSUndoManagerDidUndoChange, object: self.undoManager!)
        NotificationCenter.default.addObserver(self, selector: #selector(self.updateUndoRedoButtonState), name: .NSUndoManagerDidRedoChange, object: self.undoManager!)
    }

    func updateLayout(for toolPicker: PKToolPicker) {
        let obscuredFrame = toolPicker.frameObscured(in: view)
        
        // if there is no obscured frame, the tool picker is floating
        // which means we don't need to change inset or show undo/redo
        if obscuredFrame.isNull {
            navigationItem.leftBarButtonItems = [cancelBarButtonItem]
            canvasView.contentInset = .zero
            canvasView.automaticallyAdjustsScrollIndicatorInsets = true
        } else {
            navigationItem.leftBarButtonItems = [cancelBarButtonItem, undoBarButtonItem, redoBarButtonItem]
            canvasView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: obscuredFrame.height, right: 0)
            canvasView.automaticallyAdjustsScrollIndicatorInsets = false
            // we don't care about the botom safe area inset becaused the tool picker obscured frame includes the safe area
            canvasView.scrollIndicatorInsets = UIEdgeInsets(top: view.safeAreaInsets.top, left: view.safeAreaInsets.left, bottom: obscuredFrame.height, right: view.safeAreaInsets.right)
        }
    }
    
    func updateContentSizeForDrawing() {
        let overscrollAmount: CGFloat = 100
        let drawingBounds = canvasView.drawing.bounds
        let newSize: CGSize
        if !drawingBounds.isNull {
            let width = max(canvasView.bounds.width, (drawingBounds.maxX + overscrollAmount) * canvasView.zoomScale)
            let height = max(canvasView.bounds.height, (drawingBounds.maxY + overscrollAmount) * canvasView.zoomScale)
            newSize = CGSize(width: width, height: height)
        } else {
            newSize = canvasView.bounds.size
        }
        canvasView.contentSize = newSize
    }
    
    @objc func updateUndoRedoButtonState() {
        undoBarButtonItem.isEnabled = undoManager!.canUndo
        redoBarButtonItem.isEnabled = undoManager!.canRedo
    }
    
    // MARK: Interaction
    
    @objc func cancelPressed() {
        delegate?.composeDrawingViewControllerClose(self)
    }
    
    @objc func savePressed() {
        delegate?.composeDrawingViewController(self, saveDrawing: canvasView.drawing)
    }
    
    @objc func undoPressed() {
        undoManager!.undo()
    }
    
    @objc func redoPressed() {
        undoManager!.redo()
    }

}

extension ComposeDrawingViewController: PKCanvasViewDelegate {
    func canvasViewDrawingDidChange(_ canvasView: PKCanvasView) {
        if !undoManager!.isUndoing && !undoManager!.isRedoing {
            updateUndoRedoButtonState()
        }
        updateContentSizeForDrawing()
    }
}

extension ComposeDrawingViewController: PKToolPickerObserver {
    func toolPickerFramesObscuredDidChange(_ toolPicker: PKToolPicker) {
        updateLayout(for: toolPicker)
    }
    
    func toolPickerVisibilityDidChange(_ toolPicker: PKToolPicker) {
        updateLayout(for: toolPicker)
    }
}
