//
//  DropUpMenu.swift
//  DropUpMenu
//
//  Created by Suric on 16/8/11.
//  Copyright © 2016年 teambition. All rights reserved.
//

import UIKit

public protocol DropUpMenuDelegate: class {
    func dropUpMenu(_ dropUpMenu: DropUpMenu, cellForRowAt indexPath: IndexPath) -> UITableViewCell?
    func dropUpMenu(_ dropUpMenu: DropUpMenu, didSelectRowAt indexPath: IndexPath)
    func dropUpMenuCancel(_ dropUpMenu: DropUpMenu)
    func dropUpMenuWillDismiss(_ dropUpMenu: DropUpMenu)
    func dropUpMenuWillShow(_ dropUpMenu: DropUpMenu)
}

public extension DropUpMenuDelegate {
    func dropUpMenu(_ dropUpMenu: DropUpMenu, cellForRowAt indexPath: IndexPath) -> UITableViewCell? {
        return nil
    }
    
    func dropUpMenu(_ dropUpMenu: DropUpMenu, didSelectRowAt indexPath: IndexPath) { }
    
    func dropUpMenuCancel(_ dropUpMenu: DropUpMenu) { }
  
    func dropUpMenuWillDismiss(_ dropUpMenu: DropUpMenu) { }
  
    func dropUpMenuWillShow(_ dropUpMenu: DropUpMenu) { }
}

private let screenRect = UIScreen.main.bounds

open class DropUpMenu: UIView {
    fileprivate var items: [DropdownItem] = []
    fileprivate var selectedRow: Int
    open var tableView: UITableView!
    fileprivate var barCoverView: UIView!
    fileprivate var isShow = false
    fileprivate var addedWindow: UIWindow?
    fileprivate var windowRootView: UIView?
    fileprivate lazy var tapGestureRecognizer: UITapGestureRecognizer = {
        return UITapGestureRecognizer(target: self, action: #selector(self.hideMenu))
    }()
    
    open weak var delegate: DropUpMenuDelegate?
    
    open var animateDuration: TimeInterval = 0.25
    
    open var backgroudBeginColor: UIColor = UIColor.black.withAlphaComponent(0)
    open var backgroudEndColor = UIColor(white: 0, alpha: 0.4)
    
    open var rowHeight: CGFloat = 50
    open var tableViewHeight: CGFloat = 0
    open var defaultBottonMargin: CGFloat = 150
    
    open var textColor: UIColor = UIColor(red: 56.0/255.0, green: 56.0/255.0, blue: 56.0/255.0, alpha: 1.0)
    open var highlightColor: UIColor = UIColor(red: 3.0/255.0, green: 169.0/255.0, blue: 244.0/255.0, alpha: 1.0)
    open var tableViewBackgroundColor: UIColor = UIColor(red: 242.0/255.0, green: 242.0/255.0, blue: 242.0/255.0, alpha: 1.0) {
        didSet {
            tableView.backgroundColor = tableViewBackgroundColor
        }
    }
    open var tableViewSeperatorColor = UIColor(red: 217.0/255.0, green: 217.0/255.0, blue: 217.0/255.0, alpha: 1.0) {
        didSet {
            tableView.separatorColor = tableViewSeperatorColor
        }
    }
    open var cellBackgroundColor = UIColor.white

    open var displaySelected: Bool = true
    open var bottomOffsetY: CGFloat = 0
    
    required public init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    public init(items: [DropdownItem], selectedRow: Int = 0, bottomOffsetY: CGFloat = 0) {
        self.items = items
        self.selectedRow = selectedRow
        self.bottomOffsetY = bottomOffsetY
        
        let frame = CGRect(x: 0, y: 0, width: screenRect.width, height: screenRect.height - bottomOffsetY)
        super.init(frame: frame)
        
        clipsToBounds = true
        setupGestureView()
        initTableView()
    }
    
    fileprivate func setupGestureView() {
        let gestureView = UIView()
        gestureView.backgroundColor = UIColor.clear
        addSubview(gestureView)
        gestureView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([NSLayoutConstraint.init(item: gestureView, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1.0, constant: 0)])
        NSLayoutConstraint.activate([NSLayoutConstraint.init(item: gestureView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1.0, constant: 0)])
        NSLayoutConstraint.activate([NSLayoutConstraint.init(item: gestureView, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1.0, constant: 0)])
        NSLayoutConstraint.activate([NSLayoutConstraint.init(item: gestureView, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1.0, constant: 0)])
        
        gestureView.addGestureRecognizer(tapGestureRecognizer)
    }
    
    fileprivate func initTableView() {
        tableView = UITableView(frame: CGRect.zero, style: .grouped)
        tableView?.delegate = self
        tableView?.dataSource = self
        tableView.estimatedSectionHeaderHeight = 0
        tableView.estimatedSectionFooterHeight = 0
        addSubview(tableView)
    }
    
    fileprivate func layoutTableView() {
        tableViewHeight = CGFloat(items.count) * rowHeight
        let maxHeight = UIScreen.main.bounds.height - bottomOffsetY
        if tableViewHeight > maxHeight {
            tableViewHeight = maxHeight
        }
        
        tableView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([NSLayoutConstraint.init(item: tableView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1.0, constant:0)])
        NSLayoutConstraint.activate([NSLayoutConstraint.init(item: tableView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: tableViewHeight)])
        NSLayoutConstraint.activate([NSLayoutConstraint.init(item: tableView, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1.0, constant: 0)])
        NSLayoutConstraint.activate([NSLayoutConstraint.init(item: tableView, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1.0, constant: 0)])
    }
    
    fileprivate func setupBottomSeperatorView() {
        let seperatorView = UIView()
        seperatorView.backgroundColor = tableViewSeperatorColor
        addSubview(seperatorView)
        seperatorView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([NSLayoutConstraint.init(item: seperatorView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1.0, constant: 0)])
        NSLayoutConstraint.activate([NSLayoutConstraint.init(item: seperatorView, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1.0, constant: 0)])
        NSLayoutConstraint.activate([NSLayoutConstraint.init(item: seperatorView, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1.0, constant: 0)])
        NSLayoutConstraint.activate([NSLayoutConstraint.init(item: seperatorView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 0.5)])
    }
    
    fileprivate func setupBottomCoverView(on view: UIView) {
        barCoverView = UIView()
        barCoverView.backgroundColor = UIColor.clear
        barCoverView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(barCoverView)
        NSLayoutConstraint.activate([NSLayoutConstraint.init(item: barCoverView, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1.0, constant: 0)])
        NSLayoutConstraint.activate([NSLayoutConstraint.init(item: barCoverView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: bottomOffsetY)])
        NSLayoutConstraint.activate([NSLayoutConstraint.init(item: barCoverView, attribute: .left, relatedBy: .equal, toItem: view, attribute: .left, multiplier: 1.0, constant: 0)])
        NSLayoutConstraint.activate([NSLayoutConstraint.init(item: barCoverView, attribute: .right, relatedBy: .equal, toItem: view, attribute: .right, multiplier: 1.0, constant: 0)])
        barCoverView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(hideMenu)))
    }
    
    open func showMenu() {
        delegate?.dropUpMenuWillShow(self)
        if isShow {
            hideMenu()
            return
        }
        isShow = true
        
        layoutTableView()
        setupBottomSeperatorView()
        
        if let rootView = UIApplication.shared.keyWindow {
            windowRootView = rootView
        } else {
            addedWindow = UIWindow(frame: UIScreen.main.bounds)
            addedWindow?.rootViewController = UIViewController()
            addedWindow?.isHidden = false
            addedWindow?.makeKeyAndVisible()
            windowRootView = addedWindow!
        }
        setupBottomCoverView(on: windowRootView!)
        windowRootView?.addSubview(self)
        
        translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([NSLayoutConstraint.init(item: self, attribute: .top, relatedBy: .equal, toItem: windowRootView, attribute: .top, multiplier: 1.0, constant: 0)])
        NSLayoutConstraint.activate([NSLayoutConstraint.init(item: self, attribute: .bottom, relatedBy: .equal, toItem: windowRootView, attribute: .bottom, multiplier: 1.0, constant: -bottomOffsetY)])
        NSLayoutConstraint.activate([NSLayoutConstraint.init(item: self, attribute: .left, relatedBy: .equal, toItem: windowRootView, attribute: .left, multiplier: 1.0, constant: 0)])
        NSLayoutConstraint.activate([NSLayoutConstraint.init(item: self, attribute: .right, relatedBy: .equal, toItem: windowRootView, attribute: .right, multiplier: 1.0, constant: 0)])
        
        backgroundColor = backgroudBeginColor
        self.tableView.frame.origin.y = screenRect.height - bottomOffsetY
        UIView.animate(withDuration: animateDuration, delay: 0, options: UIView.AnimationOptions(rawValue: 7<<16), animations: {
            self.backgroundColor = self.backgroudEndColor
            self.tableView.frame.origin.y = screenRect.height - self.bottomOffsetY - self.tableViewHeight
            }, completion: nil)
    }
    
    @objc open func hideMenu(isSelectAction: Bool = false) {
        delegate?.dropUpMenuWillDismiss(self)
        UIView.animate(withDuration: animateDuration, animations: {
            self.backgroundColor = self.backgroudBeginColor
            self.tableView.frame.origin.y = screenRect.height - self.bottomOffsetY
        }, completion: { (finished) in
            if !isSelectAction {
                self.delegate?.dropUpMenuCancel(self)
            }

            self.barCoverView.removeFromSuperview()
            self.removeFromSuperview()
            self.isShow = false
            
            if let _ = self.addedWindow {
                self.addedWindow?.isHidden = true
                UIApplication.shared.keyWindow?.makeKey()
            }
        }) 
    }
}

extension DropUpMenu: UITableViewDataSource {
    public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.count
    }
    
    public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if let customCell = delegate?.dropUpMenu(self, cellForRowAt: indexPath) {
            return customCell
        }
        
        let item = items[(indexPath as NSIndexPath).row]
        let cell = UITableViewCell(style: .default, reuseIdentifier: "dropUpMenuCell")
        
        switch item.style {
        case .default:
            cell.textLabel?.textColor = textColor
            if let image = item.image {
                cell.imageView?.image = image
            }
        case .highlight:
            cell.textLabel?.textColor = highlightColor
            if let image = item.image {
                let highlightImage = image.withRenderingMode(.alwaysTemplate)
                cell.imageView?.image = highlightImage
                cell.imageView?.tintColor = highlightColor
            }
        }
        
        cell.textLabel?.text = item.title
        cell.tintColor = highlightColor
        cell.backgroundColor = cellBackgroundColor
        
        if displaySelected && (indexPath as NSIndexPath).row == selectedRow {
            cell.accessoryType = .checkmark
        } else {
            cell.accessoryType = .none
        }
        
        if let accesoryImage = item.accessoryImage {
            cell.accessoryView = UIImageView(image: accesoryImage)
        }
        
        return cell
    }
}

extension DropUpMenu: UITableViewDelegate {
    public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return rowHeight
    }

    public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return CGFloat.leastNonzeroMagnitude
    }
    
    public func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        return CGFloat.leastNormalMagnitude
    }
    
    public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if displaySelected {
            let item = items[(indexPath as NSIndexPath).row]
            if item.accessoryImage  == nil {
                let previousSelectedcell = tableView.cellForRow(at: IndexPath(row: selectedRow, section: 0))
                previousSelectedcell?.accessoryType = .none
                selectedRow = (indexPath as NSIndexPath).row
                let cell = tableView.cellForRow(at: indexPath)
                cell?.accessoryType = .checkmark
            }
        }
        tableView.deselectRow(at: indexPath, animated: true)
        hideMenu(isSelectAction: true)
        delegate?.dropUpMenu(self, didSelectRowAt: indexPath)
    }
}