//
//  IconButtons.swift

//
//  Created by Leon on 2025/7/18.
//

import UIKit

enum IconButtonStyle: UInt {
    case primary
    case secondary
    case tertiary
    case ghost
    case tertiaryRoundDark
    case tertiaryRoundLight
}

enum IconSize: Int {
    /// 24->21
    case large = 21
    /// 20
    case medium = 20
    /// 16
    case small = 16
    /// 12
    case xs = 12
    /// 10
    case xs10 = 10
    /// 8
    case xxs = 8
}

enum IconButtonRadius: UInt {
    case none
    case rectangle
    case round
}

// Base class: Typically use subclasses below
class EPIconButton: CLButton {
    var style: IconButtonStyle
    var iconSize: IconSize
    var iconCode: IconCode
    var radius: IconButtonRadius

    init(style: IconButtonStyle, radius: IconButtonRadius, iconSize: IconSize, iconCode: IconCode) {
        self.style = style
        self.iconSize = iconSize
        self.iconCode = iconCode
        self.radius = radius
        super.init(frame: .zero)

        clipsToBounds = true
        setupRadius()
        setupTapExpand()
        setupTheme()
    }

    convenience init(radius: IconButtonRadius, iconSize: IconSize, iconCode: IconCode) {
        self.init(style: .primary, radius: radius, iconSize: iconSize, iconCode: iconCode)
    }

    @available(*, unavailable)
    override init(frame: CGRect) {
        fatalError("init(frame:) has not been implemented")
    }

    @available(*, unavailable)
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func update(radius: IconButtonRadius, iconSize: IconSize, iconCode: IconCode) {
        self.iconSize = iconSize
        self.iconCode = iconCode
        self.radius = radius
        setupRadius()
        setupTapExpand()
        setupTheme()
    }

    var iconCodeValue: IconCode {
        get { iconCode }
        set {
            iconCode = newValue
            setupTheme()
        }
    }

    func setupTheme() {
        // Override in subclasses
    }

    func setupRadius() {
        switch radius {
        case .rectangle:
            layer.cornerRadius = 8
        case .round:
            layer.cornerRadius = bgImageSize().height * 0.5
        case .none:
            layer.cornerRadius = 0
            break
        }
    }

    func setupTapExpand() {
        let bgImageSize = bgImageSize()
        let expand = 48 - bgImageSize.width
        touchAreaInsets = UIEdgeInsets(top: expand, left: expand, bottom: expand, right: expand)
    }

    func bgImageSize() -> CGSize {
        switch iconSize {
        case .large: return CGSize(width: 48, height: 48)
        case .medium: return CGSize(width: 36, height: 36)
        case .small: return CGSize(width: 32, height: 32)
        case .xs: return CGSize(width: 24, height: 24)
        case .xs10: return CGSize(width: 20, height: 20)
        case .xxs: return CGSize(width: 16, height: 16)
        }
    }

    func makeIcon(color: UIColor) -> UIImage {
        return MWIconFont.image(fromIconInt: iconCode.rawValue, size: CGSize(width: iconSize.rawValue, height: iconSize.rawValue), color: color, edgeInsets: .zero)!
    }

    func makeBGImage(colors: UIColor) -> UIImage {
        let bgImageSize = bgImageSize()
        return UIImage.withColor(color: colors, size: bgImageSize)
    }

    func makeBGCircleBGImage(color: UIColor) -> UIImage {
        let bgImageSize = bgImageSize()
        let bounds = CGRect(origin: .zero, size: bgImageSize)
        return UIImage.circleImage(withColor: color, bounds: bounds)!
    }

    func makeBGGradientImage(token: EPGradient) -> UIImage {
        var colors: [UIColor] = []
        if let firstColor = token.firstColor {
            colors.append(firstColor)
        }
        if let secondColor = token.secondColor {
            colors.append(secondColor)
        }
        let bgImageSize = bgImageSize()
        return UIImage.gradientHImageWithSize(size: bgImageSize, colors: colors)
    }

    func setupTapExpandEdge(insets: UIEdgeInsets) {
        touchAreaInsets = insets
    }
}

// MARK: - EPIconPrimaryButton

class EPIconPrimaryButton: EPIconButton {
    convenience init(radius: IconButtonRadius, iconSize: IconSize, iconCode: IconCode) {
        self.init(style: .primary, radius: radius, iconSize: iconSize, iconCode: iconCode)
    }

    override func setupTheme() {
        let normalColor = UIColor.c.ctpn // EPSystemToken.color(.txtPrimarySpecialmapNormal)
        let disabledColor = UIColor.c.ctpd // EPSystemToken.color(.txtPrimaryDisabled)

        setImage(makeIcon(color: normalColor), for: .normal)
        setImage(makeIcon(color: normalColor), for: .highlighted)
        setImage(makeIcon(color: disabledColor), for: .disabled)

        let normalGradient = CLSystemToken.gradient(token: .cpgn) // EPSystemToken.gradient(.primaryGradientNormal)
        let pressGradient = CLSystemToken.gradient(token: .cpgp) // EPSystemToken.gradient(.primaryGradientPress)
        let disabledGradient = CLSystemToken.gradient(token: .csed) // EPSystemToken.gradient(.surfaceElementDisabled)

        setBackgroundImage(makeBGGradientImage(token: normalGradient), for: .normal)
        setBackgroundImage(makeBGGradientImage(token: pressGradient), for: .highlighted)
        setBackgroundImage(makeBGGradientImage(token: disabledGradient), for: .disabled)
    }
}

// MARK: - EPIconSecondaryButton

class EPIconSecondaryButton: EPIconButton {
    convenience init(iconSize: IconSize, iconCode: IconCode) {
        self.init(style: .secondary, radius: .none, iconSize: iconSize, iconCode: iconCode)
    }

    override func setupTheme() {
        layer.borderColor = UIColor.c.cpvn.cgColor // EPSystemToken.color(.primaryVariantNormal).cgColor

        let normalColor: UIColor = .c.cpvn // EPSystemToken.color(.primaryVariantNormal)
        let disabledColor: UIColor = .c.cpvd // EPSystemToken.color(.primaryVariantDisabled)
        let pressColor: UIColor = .c.cpvp // EPSystemToken.color(.primaryVariantPress)

        setImage(makeIcon(color: normalColor), for: .normal)
        setImage(makeIcon(color: disabledColor), for: .disabled)
        setImage(makeIcon(color: pressColor), for: .highlighted)
    }

    override func bgImageSize() -> CGSize {
        switch iconSize {
        case .large: return CGSize(width: 48, height: 48)
        case .medium: return CGSize(width: 36, height: 36)
        case .small: return CGSize(width: 32, height: 32)
        case .xs: return CGSize(width: 24, height: 24)
        default: return .zero
        }
    }
}

// MARK: - EPIconTertiaryButton

class EPIconTertiaryButton: EPIconButton {
    var optionalIconColor: UIColor? {
        didSet {
            if let color = optionalIconColor {
                setImage(makeIcon(color: color), for: .normal)
                setImage(makeIcon(color: color), for: .highlighted)
                setImage(makeIcon(color: color), for: .selected)
            }
        }
    }

    var optionalBackgroundColor: UIColor? {
        didSet {
            if let color = optionalBackgroundColor {
                setBackgroundImage(makeBGImage(colors: color), for: .normal)
                setBackgroundImage(makeBGImage(colors: color), for: .disabled)
                setBackgroundImage(makeBGImage(colors: color), for: .highlighted)
            }
        }
    }

    convenience init(radius: IconButtonRadius, iconSize: IconSize, iconCode: IconCode) {
        self.init(style: .primary, radius: radius, iconSize: iconSize, iconCode: iconCode)
    }

    override func setupTheme() {
        let normalColor: UIColor = .c.ctpn // EPSystemToken.color(.txtPrimaryNormal)
        let disabledColor: UIColor = .c.ctd // EPSystemToken.color(.txtDisabled)

        setImage(makeIcon(color: normalColor), for: .normal)
        setImage(makeIcon(color: disabledColor), for: .disabled)
        setImage(makeIcon(color: normalColor), for: .highlighted)
        setImage(makeIcon(color: normalColor), for: .selected)

        let normalBgColor: UIColor = .c.csen // EPSystemToken.color(.surfaceElementNormal)
        let disabledBgColor: UIColor = .c.csed // EPSystemToken.color(.surfaceElementDisabled)
        let pressBgColor: UIColor = .c.csep // EPSystemToken.color(.surfaceElementPress)

        setBackgroundImage(makeBGImage(colors: normalBgColor), for: .normal)
        setBackgroundImage(makeBGImage(colors: disabledBgColor), for: .disabled)
        setBackgroundImage(makeBGImage(colors: pressBgColor), for: .highlighted)
    }

    func clearBackgroundImage() {
        setBackgroundImage(nil, for: .normal)
    }

    func resumeBackgroundImage() {
        let normalBgColor: UIColor = .c.csen // EPSystemToken.color(.surfaceElementNormal)
        setBackgroundImage(makeBGImage(colors: normalBgColor), for: .normal)
    }
}

// MARK: - EPIconGhostButton

class EPIconGhostButton: EPIconButton {
    var optionalIconColor: UIColor? {
        didSet {
            if let color = optionalIconColor {
                setImage(makeIcon(color: color), for: .normal)
                setImage(makeIcon(color: color), for: .highlighted)
                setImage(makeIcon(color: color), for: .selected)
            }
        }
    }
    
    convenience init(radius: IconButtonRadius, iconSize: IconSize, iconCode: IconCode) {
        self.init(style: .ghost, radius: radius, iconSize: iconSize, iconCode: iconCode)
    }

    override func setupTheme() {
        let normalColor: UIColor = .c.ctpn // EPSystemToken.color(.txtPrimaryNormal)
        let disabledColor: UIColor = .c.ctd // EPSystemToken.color(.txtDisabled)

        setImage(makeIcon(color: normalColor), for: .normal)
        setImage(makeIcon(color: disabledColor), for: .disabled)
        setImage(makeIcon(color: normalColor), for: .highlighted)

        let pressBgColor: UIColor = .c.csep // EPSystemToken.color(.surfaceElementPress)

        setBackgroundImage(nil, for: .normal)
        setBackgroundImage(nil, for: .disabled)
        setBackgroundImage(makeBGCircleBGImage(color: pressBgColor), for: .highlighted)
    }
}

// MARK: - EPIconGhostSecondaryButton

class EPIconGhostSecondaryButton: EPIconButton {
    convenience init(radius: IconButtonRadius, iconSize: IconSize, iconCode: IconCode) {
        self.init(style: .ghost, radius: .round, iconSize: iconSize, iconCode: iconCode)
    }

    override func setupTheme() {
        let normalColor: UIColor = .c.ctsn // EPSystemToken.color(.txtSecondaryNormal)
        let disabledColor: UIColor = .c.ctsd // EPSystemToken.color(.txtSecondaryDisabled)

        setImage(makeIcon(color: normalColor), for: .normal)
        setImage(makeIcon(color: disabledColor), for: .disabled)
        setImage(makeIcon(color: normalColor), for: .highlighted)

        let pressBgColor: UIColor = .c.csep // EPSystemToken.color(.surfaceElementPress)

        setBackgroundImage(nil, for: .normal)
        setBackgroundImage(nil, for: .disabled)
        setBackgroundImage(makeBGCircleBGImage(color: pressBgColor), for: .highlighted)
    }
}

// MARK: - EPIconContrastTertiaryButton

class EPIconContrastTertiaryButton: EPIconButton {
    convenience init(radius: IconButtonRadius, iconSize: IconSize, iconCode: IconCode) {
        self.init(style: .ghost, radius: .round, iconSize: iconSize, iconCode: iconCode)
    }

    override func setupTheme() {
        let normalColor: UIColor = .c.ctpn // EPSystemToken.color(.txtPrimaryNormal)
        let disabledColor: UIColor = .c.ctd // EPSystemToken.color(.txtDisabled)

        setImage(makeIcon(color: normalColor), for: .normal)
        setImage(makeIcon(color: disabledColor), for: .disabled)
        setImage(makeIcon(color: normalColor), for: .highlighted)
        setImage(makeIcon(color: normalColor), for: .selected)

        let normalBgColor: UIColor = .c.csedn // EPSystemToken.color(.surfaceElementDarkNormal)
        let disabledBgColor: UIColor = .c.csedd // EPSystemToken.color(.surfaceElementDarkDisabled)
        let pressBgColor: UIColor = .c.csedp // EPSystemToken.color(.surfaceElementDarkPress)

        setBackgroundImage(makeBGImage(colors: normalBgColor), for: .normal)
        setBackgroundImage(makeBGImage(colors: disabledBgColor), for: .disabled)
        setBackgroundImage(makeBGImage(colors: pressBgColor), for: .highlighted)
    }
}

// MARK: - EPFloatingButton

class EPFloatingButton: EPIconButton {
    convenience init(radius: IconButtonRadius, iconSize: IconSize, iconCode: IconCode) {
        self.init(style: .ghost, radius: .round, iconSize: iconSize, iconCode: iconCode)
    }

    override func setupTheme() {
        setupNormalMode()
    }

    func setupNormalMode() {
        let normalColor: UIColor = .c.ctpn // EPSystemToken.color(.txtPrimaryNormal)
        let disabledColor: UIColor = .c.ctpsd // EPSystemToken.color(.txtPrimarySpecialmapDisable)

        setImage(makeIcon(color: normalColor), for: .normal)
        setImage(makeIcon(color: disabledColor), for: .disabled)
        setImage(makeIcon(color: normalColor), for: .highlighted)

        let pressGradient = CLSystemToken.gradient(token: .cpgp) // EPSystemToken.gradient(.primaryGradientPress)
        let gradient = CLSystemToken.gradient(token: .cpgn) // EPSystemToken.gradient(.primaryGradientNormal)
        let disabledBgColor = UIColor.c.csfn // EPSystemToken.color(.surfaceFloatNormal)

        setBackgroundImage(gradient.toImage(size: CGSize(width: 10, height: 10)), for: .normal)
        setBackgroundImage(makeBGImage(colors: disabledBgColor), for: .disabled)
        setBackgroundImage(pressGradient.toImage(size: CGSize(width: 10, height: 10)), for: .highlighted)

        layer.removeAllAnimations()
    }

    func setupMatchingState() {
        let normalColor: UIColor = .c.ctpn // EPSystemToken.color(.txtPrimaryNormal)
        let disabledColor: UIColor = .c.ctd // EPSystemToken.color(.txtDisabled)

        setImage(makeIcon(color: normalColor), for: .normal)
        setImage(makeIcon(color: disabledColor), for: .disabled)
        setImage(makeIcon(color: normalColor), for: .highlighted)

        let pressGradient = CLSystemToken.gradient(token: .cpgp) // EPSystemToken.gradient(.positiveGradientPress)
        let gradient = CLSystemToken.gradient(token: .cpgn) // EPSystemToken.gradient(.positiveGradientNormal)
        let disabledBgColor: UIColor = .c.csfn // EPSystemToken.color(.surfaceFloatNormal)

        setBackgroundImage(gradient.toImage(size: CGSize(width: 10, height: 10)), for: .normal)
        setBackgroundImage(makeBGImage(colors: disabledBgColor), for: .disabled)
        setBackgroundImage(pressGradient.toImage(size: CGSize(width: 10, height: 10)), for: .highlighted)

        let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
        rotationAnimation.toValue = NSNumber(value: Double.pi * 2.0)
        rotationAnimation.duration = 1.5
        rotationAnimation.isRemovedOnCompletion = false
        rotationAnimation.isCumulative = true
        rotationAnimation.repeatCount = .infinity
        layer.add(rotationAnimation, forKey: "rotationAnimation")
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        if radius == .round {
            layer.cornerRadius = bounds.size.height * 0.5
        }
    }

    deinit {
        layer.removeAllAnimations()
    }
}

// MARK: - EPIconTertiaryDarkButton

class EPIconTertiaryDarkButton: EPIconButton {
    convenience init(radius: IconButtonRadius, iconSize: IconSize, iconCode: IconCode) {
        self.init(style: .tertiaryRoundDark, radius: radius, iconSize: iconSize, iconCode: iconCode)
    }

    override func setupTheme() {
        let normalColor: UIColor = .c.ctpsn // EPSystemToken.color(.txtPrimarySpecialmapNormal)
        let disabledColor: UIColor = .c.ctpd // EPSystemToken.color(.txtPrimaryDisabled)

        setImage(makeIcon(color: normalColor), for: .normal)
        setImage(makeIcon(color: disabledColor), for: .disabled)
        setImage(makeIcon(color: normalColor), for: .highlighted)

        let normalBgColor: UIColor = .c.csedn // EPSystemToken.color(.surfaceElementDarkNormal)
        let disabledBgColor: UIColor = .c.csedd // EPSystemToken.color(.surfaceElementDarkDisabled)
        let pressBgColor: UIColor = .c.csedp // EPSystemToken.color(.surfaceElementDarkPress)

        setBackgroundImage(makeBGImage(colors: normalBgColor), for: .normal)
        setBackgroundImage(makeBGImage(colors: disabledBgColor), for: .disabled)
        setBackgroundImage(makeBGImage(colors: pressBgColor), for: .highlighted)
    }

    func clearBackgroundImage() {
        setBackgroundImage(nil, for: .normal)
    }

    func resumeBackgroundImage() {
        let normalBgColor:UIColor = .c.csedn//EPSystemToken.color(.surfaceElementDarkNormal)
        setBackgroundImage(makeBGImage(colors: normalBgColor), for: .normal)
    }
}

// MARK: - EPIconTertiaryLightButton

class EPIconTertiaryLightButton: EPIconButton {
    convenience init(radius: IconButtonRadius, iconSize: IconSize, iconCode: IconCode) {
        self.init(style: .tertiaryRoundLight, radius: radius, iconSize: iconSize, iconCode: iconCode)
    }

    override func setupTheme() {
        let normalColor: UIColor = .c.ctpsn//EPSystemToken.color(.txtPrimarySpecialmapNormal)
        let disabledColor: UIColor = .c.ctpsd//EPSystemToken.color(.txtPrimarySpecialmapDisable)

        setImage(makeIcon(color: normalColor), for: .normal)
        setImage(makeIcon(color: disabledColor), for: .disabled)
        setImage(makeIcon(color: normalColor), for: .highlighted)

        let normalBgColor: UIColor = .c.cseln//EPSystemToken.color(.surfaceElementLightNormal)
        let disabledBgColor: UIColor = .c.cseld//EPSystemToken.color(.surfaceElementLightDisabled)
        let pressBgColor: UIColor = .c.cselp//EPSystemToken.color(.surfaceElementLightPress)

        setBackgroundImage(makeBGImage(colors: normalBgColor), for: .normal)
        setBackgroundImage(makeBGImage(colors: disabledBgColor), for: .disabled)
        setBackgroundImage(makeBGImage(colors: pressBgColor), for: .highlighted)
    }
}

class EPIconDestructiveButton : EPIconButton{
    override func setupTheme() {
        let normalColor: UIColor = .c.ctpn
        let disabledColor: UIColor = .c.ctpd

        setImage(makeIcon(color: normalColor), for: .normal)
        setImage(makeIcon(color: disabledColor), for: .disabled)
        setImage(makeIcon(color: normalColor), for: .highlighted)

        let normalBgColor: UIColor = .c.cin
        let disabledBgColor: UIColor = .c.cid
        let pressBgColor: UIColor = .c.cip

        setBackgroundImage(makeBGImage(colors: normalBgColor), for: .normal)
        setBackgroundImage(makeBGImage(colors: disabledBgColor), for: .disabled)
        setBackgroundImage(makeBGImage(colors: pressBgColor), for: .highlighted)
    }
}
