//
//  ReliefButton.swift
//  App
//
//  Created by James Magahern on 8/14/20.
//

import UIKit

class ReliefButton: UIButton
{
    public var constrainedToSquare = true
    
    internal var cornerRadius = CGFloat(6.0) { didSet { setNeedsLayout() } }
    internal let shadowView = UIView(frame: .zero)
    internal let backgroundView = GradientView(direction: .vertical, colors: ReliefButton.gradientColors(inverted: false, darkMode: false))
    
    static let padding = CGFloat(24.0)
    static let borderWidth = CGFloat(1.0 / UIScreen.main.scale)
    
    override var isHighlighted: Bool {
        get {
            super.isHighlighted || remainsPressed
        }
        
        set {
            super.isHighlighted = newValue
            setBackgroundInverted(isHighlighted)
        }
    }
    
    var remainsPressed: Bool = false {
        didSet {
            self.isHighlighted = remainsPressed
        }
    }
    
    init() {
        super.init(frame: .zero)
        
        self.tintColor = .init(dynamicProvider: { traitCollection -> UIColor in
            if traitCollection.userInterfaceStyle == .light {
                return .init(white: 0.15, alpha: 1.0)
            } else {
                return .white
            }
        })
        
        self.imageView?.contentMode = .scaleAspectFit
        
        shadowView.alpha = 0.28
        shadowView.backgroundColor = UIColor(white: 0.0, alpha: 1.0)
        shadowView.isUserInteractionEnabled = false
        shadowView.layer.shadowColor = UIColor.black.cgColor
        shadowView.layer.shadowOffset = CGSize(width: 0.0, height: 1.0)
        shadowView.layer.shadowRadius = 1.0
        shadowView.layer.shadowOpacity = 1.0
        shadowView.layer.masksToBounds = false
        shadowView.layer.shouldRasterize = true
        shadowView.layer.rasterizationScale = UIScreen.main.scale
        shadowView.layer.cornerCurve = .continuous
        addSubview(shadowView)
        
        backgroundView.isUserInteractionEnabled = false
        backgroundView.layer.masksToBounds = true
        backgroundView.layer.borderWidth = Self.borderWidth
        backgroundView.layer.cornerCurve = .continuous
        backgroundView.layer.shouldRasterize = true
        backgroundView.layer.rasterizationScale = UIScreen.main.scale
        addSubview(backgroundView)
        
        registerForTraitChanges([UITraitUserInterfaceStyle.self], handler: handleTraitCollectionChange)
        
        pointerStyleProvider = { (button, pointerEffect, pointerShape) -> UIPointerStyle? in
            let preview = UITargetedPreview(view: button)
            return UIPointerStyle(effect: .lift(preview), shape: pointerShape)
        }
        
        handleTraitCollectionChange(self, previousCollection: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    static func gradientColors(inverted: Bool, darkMode: Bool) -> [UIColor] {
        let colors = { darkMode -> [UIColor] in
            if darkMode {
                return [
                    UIColor(white: 0.15, alpha: 1.0),
                    UIColor(white: 0.08, alpha: 1.0)
                ]
            } else {
                return [
                    UIColor(white: 0.98, alpha: 1.0),
                    UIColor(white: 0.93, alpha: 1.0)
                ]
            }
        } (darkMode)
        
        return inverted ? colors.reversed() : colors
    }
    
    private func handleTraitCollectionChange(_ environment: UITraitEnvironment, previousCollection: UITraitCollection?) {
        setBackgroundInverted(isHighlighted)
        backgroundView.layer.borderColor = { traitCollection -> UIColor in
            if traitCollection.userInterfaceStyle == .dark {
                return .init(white: 0.30, alpha: 1.0)
            } else {
                return .white
            }
        } (traitCollection).cgColor
    }
    
    internal func setBackgroundInverted(_ inverted: Bool) {
        let darkMode: Bool = (traitCollection.userInterfaceStyle == .dark)
        backgroundView.colors = Self.gradientColors(inverted: inverted, darkMode: darkMode)
    }
    
    override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
        let ratio = CGFloat(0.45)
        let constantSize = round(ratio * contentRect.width)
        return CGRect(
            origin: .zero,
            size: CGSize(
                // Ensure multiple of two for proper centering.
                 width: constantSize + constantSize.truncatingRemainder(dividingBy: 2),
                height: constantSize + constantSize.truncatingRemainder(dividingBy: 2)
            )
        ).centered(inRect: contentRect)
    }
    
    override func sizeThatFits(_ size: CGSize) -> CGSize {
        let ourSize = super.sizeThatFits(size)
        return CGSize(width: ourSize.width + Self.padding, height: ourSize.height)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        sendSubviewToBack(backgroundView)
        sendSubviewToBack(shadowView)
        
        if constrainedToSquare {
            let backgroundDimension = bounds.height
            backgroundView.frame = CGRect(origin: .zero, size: CGSize(width: backgroundDimension, height: backgroundDimension))
            backgroundView.frame = backgroundView.frame.centeredX(inRect: bounds)
        } else {
            backgroundView.frame = bounds
        }
        
        shadowView.frame = backgroundView.frame
        
        let shadowPath = UIBezierPath(roundedRect: shadowView.bounds, cornerRadius: cornerRadius)
        shadowView.layer.shadowPath = shadowPath.cgPath
        
        backgroundView.layer.cornerRadius = cornerRadius
        shadowView.layer.cornerRadius = cornerRadius
    }
}
