//
//  NCPopupViewController.swift
//
//  Based on EzPopup by Huy Nguyen
//  Modified by Marino Faggiana for Nextcloud progect.
//
//  Author Marino Faggiana <marino.faggiana@nextcloud.com>
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

import UIKit

public protocol NCPopupViewControllerDelegate: AnyObject {
    
    func popupViewControllerDidDismissByTapGesture(_ sender: NCPopupViewController)
}

// optional func
public extension NCPopupViewControllerDelegate {
    func popupViewControllerDidDismissByTapGesture(_ sender: NCPopupViewController) {}
}

public class NCPopupViewController: UIViewController {
    
    private var centerYConstraint: NSLayoutConstraint?
    
    // Popup width, it's nil if width is determined by view's intrinsic size
    private(set) public var popupWidth: CGFloat?
    
    // Popup height, it's nil if width is determined by view's intrinsic size
    private(set) public var popupHeight: CGFloat?
        
    // Background alpha, default is 0.3
    public var backgroundAlpha: CGFloat = 0.3
    
    // Background color, default is black
    public var backgroundColor = UIColor.black
    
    // Allow tap outside popup to dismiss, default is true
    public var canTapOutsideToDismiss = true
    
    // Corner radius, default is 10 (0 no rounded corner)
    public var cornerRadius: CGFloat = 10
    
    // Shadow enabled, default is true
    public var shadowEnabled = true
    
    // Border enabled, default is false
    public var borderEnabled = false
    
    // Move the popup position H when show/hide keyboard
    public var keyboardPosizionEnabled = true

    // The pop up view controller. It's not mandatory.
    private(set) public var contentController: UIViewController?
    
    // The pop up view
    private(set) public var contentView: UIView?
    
    // The delegate to receive pop up event
    public weak var delegate: NCPopupViewControllerDelegate?
    
    private var containerView = UIView()
    
    // MARK: - View Life Cycle

    // NOTE: Don't use this init method
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    /**
     Init with content view controller. Your pop up content is a view controller (easiest way to design it is using storyboard)
     - Parameters:
        - contentController: Popup content view controller
        - popupWidth: Width of popup content. If it isn't set, width will be determine by popup content view intrinsic size.
        - popupHeight: Height of popup content. If it isn't set, height will be determine by popup content view intrinsic size.
     */
    public init(contentController: UIViewController, popupWidth: CGFloat? = nil, popupHeight: CGFloat? = nil) {
        super.init(nibName: nil, bundle: nil)
        
        self.contentController = contentController
        self.contentView = contentController.view
        self.popupWidth = popupWidth
        self.popupHeight = popupHeight
        
        modalPresentationStyle = .overFullScreen
        modalTransitionStyle = .crossDissolve
    }
    
    /**
     Init with content view
     - Parameters:
         - contentView: Popup content view
         - popupWidth: Width of popup content. If it isn't set, width will be determine by popup content view intrinsic size.
         - popupHeight: Height of popup content. If it isn't set, height will be determine by popup content view intrinsic size.
     */
    
    public init(contentView: UIView, popupWidth: CGFloat? = nil, popupHeight: CGFloat? = nil) {
        super.init(nibName: nil, bundle: nil)
        
        self.contentView = contentView
        self.popupWidth = popupWidth
        self.popupHeight = popupHeight
        
        modalPresentationStyle = .overFullScreen
        modalTransitionStyle = .crossDissolve
    }
    
    override public func viewDidLoad() {
        super.viewDidLoad()

        setupUI()
        setupViews()
        addDismissGesture()
        
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil);
    }
    
    // MARK: - Setup

    private func addDismissGesture() {
        
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissTapGesture(gesture:)))
        tapGesture.delegate = self
        view.addGestureRecognizer(tapGesture)
    }
    
    private func setupUI() {
        
        containerView.translatesAutoresizingMaskIntoConstraints = false
        contentView?.translatesAutoresizingMaskIntoConstraints = false
        
        view.backgroundColor = backgroundColor.withAlphaComponent(backgroundAlpha)
        
        if cornerRadius > 0 {
            contentView?.layer.cornerRadius = cornerRadius
            contentView?.layer.masksToBounds = true
        }
        
        if shadowEnabled {
            containerView.layer.shadowOpacity = 0.5
            containerView.layer.shadowColor = UIColor.black.cgColor
            containerView.layer.shadowOffset = CGSize(width: 5, height: 5)
            containerView.layer.shadowRadius = 5
        }
        
        if borderEnabled {
            containerView.layer.cornerRadius = cornerRadius
            containerView.layer.borderWidth = 0.3
            containerView.layer.borderColor = UIColor.gray.cgColor
        }
    }
    
    private func setupViews() {
        
        if let contentController = contentController {
            addChild(contentController)
        }
        
        addViews()
        addSizeConstraints()
        addCenterPositionConstraints()
    }
    
    private func addViews() {
        
        view.addSubview(containerView)
        
        if let contentView = contentView {
            containerView.addSubview(contentView)
            
            let topConstraint = NSLayoutConstraint(item: contentView, attribute: .top, relatedBy: .equal, toItem: containerView, attribute: .top, multiplier: 1, constant: 0)
            let leftConstraint = NSLayoutConstraint(item: contentView, attribute: .left, relatedBy: .equal, toItem: containerView, attribute: .left, multiplier: 1, constant: 0)
            let bottomConstraint = NSLayoutConstraint(item: contentView, attribute: .bottom, relatedBy: .equal, toItem: containerView, attribute: .bottom, multiplier: 1, constant: 0)
            let rightConstraint = NSLayoutConstraint(item: contentView, attribute: .right, relatedBy: .equal, toItem: containerView, attribute: .right, multiplier: 1, constant: 0)
            NSLayoutConstraint.activate([topConstraint, leftConstraint, bottomConstraint, rightConstraint])
        }
    }
    
    // MARK: - Add constraints
    
    private func addSizeConstraints() {
        
        if let popupWidth = popupWidth {
            let widthConstraint = NSLayoutConstraint(item: containerView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: popupWidth)
            NSLayoutConstraint.activate([widthConstraint])
        }
        
        if let popupHeight = popupHeight {
            let heightConstraint = NSLayoutConstraint(item: containerView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: popupHeight)
            NSLayoutConstraint.activate([heightConstraint])
        }
    }
    
    private func addCenterPositionConstraints() {
        
        let centerXConstraint = NSLayoutConstraint(item: containerView, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1, constant: 0)
        centerYConstraint = NSLayoutConstraint(item: containerView, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1, constant: 0)
        NSLayoutConstraint.activate([centerXConstraint, centerYConstraint!])
    }
    
    // MARK: -
    
    func addPath() {
        
        let balloon = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 250))
        balloon.backgroundColor = UIColor.clear


        let path = UIBezierPath()
        path.move(to: CGPoint(x: 0, y: 0))
        path.addLine(to: CGPoint(x: 200, y: 0))
        path.addLine(to: CGPoint(x: 200, y: 200))

        // Draw arrow
        path.addLine(to: CGPoint(x: 120, y: 200))
        path.addLine(to: CGPoint(x: 100, y: 250))
        path.addLine(to: CGPoint(x: 80, y: 200))

        path.addLine(to: CGPoint(x: 0, y: 200))
        path.close()

        let shape = CAShapeLayer()
        //shape.backgroundColor = UIColor.blue.cgColor
        shape.fillColor = UIColor.blue.cgColor
        shape.path = path.cgPath
        balloon.layer.addSublayer(shape)

        // [self.view addSubview:balloonView];

    }
    
    // MARK: - Actions
    
    @objc func dismissTapGesture(gesture: UIGestureRecognizer) {
        dismiss(animated: true) {
            self.delegate?.popupViewControllerDidDismissByTapGesture(self)
        }
    }
    
    // MARK: - Keyboard notification
    
    @objc internal func keyboardWillShow(_ notification : Notification?) {
                
        var keyboardSize = CGSize.zero
        
        if let info = notification?.userInfo {

            let frameEndUserInfoKey = UIResponder.keyboardFrameEndUserInfoKey
                    
            //  Getting UIKeyboardSize.
            if let keyboardFrame = info[frameEndUserInfoKey] as? CGRect {
                        
                let screenSize = UIScreen.main.bounds
                        
                //Calculating actual keyboard displayed size, keyboard frame may be different when hardware keyboard is attached (Bug ID: #469) (Bug ID: #381)
                let intersectRect = keyboardFrame.intersection(screenSize)
                        
                if intersectRect.isNull {
                    keyboardSize = CGSize(width: screenSize.size.width, height: 0)
                } else {
                    keyboardSize = intersectRect.size
                }
                
                if keyboardPosizionEnabled {
                                           
                    let popupDiff = screenSize.height - ((screenSize.height - (popupHeight ?? 0)) / 2)
                    let keyboardDiff = screenSize.height - keyboardSize.height
                    let diff = popupDiff - keyboardDiff
                    
                    if centerYConstraint != nil && diff > 0 {
                        centerYConstraint?.constant = -(diff + 15)
                    }
                }
            }
        }
    }
    
    @objc func keyboardWillHide(_ notification: Notification) {
        
        if keyboardPosizionEnabled {
            if centerYConstraint != nil {
                centerYConstraint?.constant = 0
            }
        }
    }
}

// MARK: - UIGestureRecognizerDelegate
extension NCPopupViewController: UIGestureRecognizerDelegate {
    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        guard let touchView = touch.view, canTapOutsideToDismiss else {
            return false
        }
        
        return !touchView.isDescendant(of: containerView)
    }
}