//
//  BadgedBarButtonItem.swift
//  BadgedBarButtonItem
//
//  Created by Maksim Artemov on 17/07/2019.
//  Copyright © 2019 Max. All rights reserved.
//

import UIKit

public enum BadgePosition {
    case left
    case right
}

public enum BadgeSize {
    case extraSmall
    case small
    case medium
    case large
}

// Define the notification name
extension Notification.Name {
    static let badgeValueDidChange = Notification.Name("badgeValueDidChange")
}

public class BadgedButtonItem: UIBarButtonItem {

    public func setBadge(with value: Int?) {
        self.badgeValue = value
    }

    public var badgeTintColor: UIColor? {
        didSet {
            lblBadge.backgroundColor = badgeTintColor
        }
    }

    public var badgeTextColor: UIColor? {
        didSet {
            lblBadge.textColor = badgeTextColor
        }
    }

    public var position: BadgePosition? = .right {
        didSet {
            if position == .left {
                self.lblBadge.frame = CGRect(x: 0,
                                             y: 0,
                                             width: badgeRadius * 2,
                                             height: badgeRadius * 2)
            } else {
                self.lblBadge.frame = CGRect(x: filterBtn.frame.maxX - badgeRadius * 2 - 5,
                                             y: 0,
                                             width: badgeRadius * 2,
                                             height: badgeRadius * 2)
            }
        }
    }

    public var hasBorder: Bool? {
        didSet {
            if hasBorder == true {
                lblBadge.layer.borderWidth = 1.0
            }
        }
    }

    public var borderColor: UIColor? = .black {
        didSet {
            lblBadge.layer.borderColor = borderColor?.cgColor
        }
    }

    public var badgeSize: BadgeSize = .medium {
        didSet {
            switch badgeSize {
            case .extraSmall:
                self.badgeRadius = 6.0
            case .small:
                self.badgeRadius = 7.0
            case .medium:
                self.badgeRadius = 8.0
            case .large:
                self.badgeRadius = 9.0
            }
        }
    }

    public var badgeAnimation: Bool? = false {
        didSet {
            self.isAnimated = badgeAnimation
        }
    }

    public var tapAction: (() -> Void)?

    private var badgeValue: Int? {
        didSet {
            if let value = badgeValue, value > 0 {
                // reducing font size if the value has two digits
                if "\(value)".count > 1 {
                    lblBadge.font = UIFont.systemFont(ofSize: twoDigitsFontSize)
                } else {
                    lblBadge.font = UIFont.systemFont(ofSize: oneDigitFontSize)
                }
                
                lblBadge.isHidden = false
                lblBadge.text = "\(value)"
                animateBadge(isAnimated)
            } else {
                lblBadge.isHidden = true
            }
            // Post notification about the change
            NotificationCenter.default.post(name: .badgeValueDidChange, object: nil, userInfo: ["badgeValue": badgeValue ?? 0])
        }
    }

    private let filterBtn = UIButton()
    private let lblBadge = UILabel()
    private var isAnimated: Bool? = false
    private var badgeRadius: CGFloat = 8.0 {
        didSet {
            self.lblBadge.layer.cornerRadius = badgeRadius
        }
    }

    private var oneDigitFontSize: CGFloat {
        return badgeRadius + 1
    }
    private var twoDigitsFontSize: CGFloat {
        return badgeRadius
    }

    override init() {
        super.init()
        setup()
    }

    init(with image: UIImage?) {
        super.init()
        setup(image: image)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    private func setup(image: UIImage? = nil) {
        self.filterBtn.frame = CGRect(x: 0, y: 0, width: 55, height: 55)
        self.filterBtn.adjustsImageWhenHighlighted = false
        let scaledImage = UIImage.imageWithImage(image, scaledToSize: CGSize(width: 45, height: 50))
        self.filterBtn.setImage(scaledImage?.withRenderingMode(.alwaysOriginal), for: .normal)
        self.filterBtn.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside)
        
        self.lblBadge.frame = CGRect(x: filterBtn.frame.maxX - badgeRadius * 2,
                                     y: 0,
                                     width: badgeRadius * 2,
                                     height: badgeRadius * 2)
        self.lblBadge.backgroundColor = .red
        self.lblBadge.clipsToBounds = true
        self.lblBadge.layer.cornerRadius = badgeRadius
        self.lblBadge.textColor = .white
        self.lblBadge.font = UIFont.systemFont(ofSize: 10)
        self.lblBadge.textAlignment = .center
        self.lblBadge.isHidden = true
        self.lblBadge.minimumScaleFactor = 0.5
        self.lblBadge.adjustsFontSizeToFitWidth = true
        self.filterBtn.addSubview(lblBadge)
        self.customView = filterBtn
    }

    @objc private func buttonPressed() {
        if let action = tapAction {
            action()
        }
    }

    private func animateBadge(_ animate: Bool?) {
        guard animate == true else { return }
        lblBadge.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
        UIView.animate(withDuration: 0.4,
                       delay: 0,
                       usingSpringWithDamping: 0.2,
                       initialSpringVelocity: 3,
                       options: [.curveLinear],
                       animations: { [weak self] in
                        
            guard let strongSelf = self else { return }
            strongSelf.lblBadge.transform = .identity
                        
        }) { [weak self] (finished) in
            
            guard let strongSelf = self else { return }
            if !finished {
                strongSelf.lblBadge.transform = .identity
            }
        }
    }
}

/// Takes an image and returns a new one identical but resized.
private extension UIImage {
    static func imageWithImage(_ image: UIImage?, scaledToSize newSize: CGSize) -> UIImage? {
        guard let image = image else { return nil }
        UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
        image.draw(in: CGRect(origin: CGPoint.zero, size: CGSize(width: newSize.width, height: newSize.height)))
        let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return newImage
    }
}
