//
//  AudioButton.swift

//
//  Created by Leon on 2025/8/1.
//

import UIKit
import SnapKit
import Lottie

enum AudioButtonEnumSize: Int {
    /// height: 48
    case large
    /// height: 32
    case medium
    /// height: 32
    case small
    /// 20x20
    case square20
    case square24
}

// Define AudioButtonStyle enum
enum AudioButtonStyle: Int {
    // Clear bg. used in AI Role create process, select voice
    case clearBg
    /// White triangle + semi-transparent black circle background
    case videoPlay
    /// 白色三角 + 主体背景色
    case voiceThemePlay
}

class AudioButton: CLButton {
    
    
    // MARK: - Properties
    var bgImageView: UIImageView!
    var leftImageView: UIImageView!
    var voiceAnimation: LottieAnimationView!
    
    private var indicator: IndicatorView!
    private var buttonSize: AudioButtonEnumSize = .medium
    private var path: String = ""
    private var iconSize: CGSize = CGSize(width: 16, height: 16)
    // MARK: - States
    var isDisplay: Bool = true {
        didSet {
            isHidden = !isDisplay
        }
    }
    
    var indicatorAnimated: Bool {
        return indicator.isAnimating
    }
    
    var audioLottieAnimated: Bool{
        return voiceAnimation.isAnimationPlaying
    }
    
    // MARK: - Initialization
    static func buttonWithSize(_ size: AudioButtonEnumSize) -> AudioButton {
        return AudioButton(size: size)
    }
    
    static func buttonWithStyle(_ style: AudioButtonStyle) -> AudioButton {
        return AudioButton(style: style)
    }
    
    convenience init(size: AudioButtonEnumSize) {
        self.init(frame: .zero)
        self.buttonSize = size
        initialViews()
    }
    
    convenience init(style: AudioButtonStyle, size:AudioButtonEnumSize = .square20) {
        self.init(frame: .zero)
        switch style {
        case .videoPlay:
            initialCirclePlayStyle()
        case .clearBg:
            initialClearBgPlayStyle()
        case .voiceThemePlay:
            initialVoiceThemePlay()
        }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        // Default initialization, but we discourage direct init
        // assertionFailure("Use buttonWithSize or buttonWithStyle instead!")
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        self.buttonSize = .medium
        initialViews()
    }
    
    // MARK: - 🚩Style 1: Traditional Audio Button
    private func initialViews() {
        isDisplay = true
        var width: CGFloat = 88
        var height: CGFloat = 48
        var cornerRadius: CGFloat = 24
        var imageEdgeInsets: UIEdgeInsets = .zero
        
        switch buttonSize {
        case .large:
            height = 48
            cornerRadius = 24
            imageEdgeInsets = UIEdgeInsets(top: 0, left: 32, bottom: 0, right: 32)
            iconSize = CGSize(width: 20, height: 20)
        case .small:
            height = 32
            width = 52
            cornerRadius = 16
            imageEdgeInsets = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
            iconSize = CGSize(width: 16, height: 16)
        case .medium:
            height = 32
            cornerRadius = 16
            imageEdgeInsets = UIEdgeInsets(top: 0, left: 32, bottom: 0, right: 32)
            iconSize = CGSize(width: 16, height: 16)
        case .square20:
            height = 20
            cornerRadius = 0
            imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
            iconSize = CGSize(width: height, height: height)
        case .square24:
            height = 24
            cornerRadius = 0
            imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
            iconSize = CGSize(width: height, height: height)
        }
        
        snp.makeConstraints { make in
            make.height.equalTo(height)
        }
        layer.cornerRadius = cornerRadius
        clipsToBounds = true
        self.imageEdgeInsets = imageEdgeInsets
        
        bgImageView = UIImageView()
        bgImageView.clipsToBounds = true
        bgImageView.image = UIImage.withColor(color: .purple, size: CGSize(width: width, height: 24))
        addSubview(bgImageView)
        bgImageView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        
        leftImageView = UIImageView()
        leftImageView.image = iconOfWhitePlay()
        addSubview(leftImageView)
        leftImageView.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.size.equalTo(CGSize(width: 14, height: 14))
        }
        
        let animation = LottieAnimation.named("voice_white")
        voiceAnimation = LottieAnimationView(animation: animation)
        // voiceAnimation = LottieAnimationView.animationNamed("voice_white.json")
        voiceAnimation.isUserInteractionEnabled = false
        voiceAnimation.loopMode = .loop
        voiceAnimation.animationSpeed = 1.4
        voiceAnimation.contentMode = .scaleAspectFit
        voiceAnimation.isHidden = true
        voiceAnimation.tintColor = .white
        addSubview(voiceAnimation)
        voiceAnimation.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.size.equalTo(CGSize(width: 14, height: 14))
        }
        
        indicator = IndicatorView(color: .white)
        indicator.size = CGSize(width: 12, height: 12)
        indicator.isHidden = true
        addSubview(indicator)
        indicator.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.size.equalTo(CGSize(width: 12, height: 12))
        }
    }
    
    // MARK: - Style(Custom) 2: Circle Play Style
    private func initialCirclePlayStyle() {
        let width: CGFloat = 32
        iconSize = CGSize(width: 16, height: 16)
        
        snp.makeConstraints { make in
            make.height.equalTo(32)
        }
        layer.cornerRadius = 16
        clipsToBounds = true
        
        bgImageView = UIImageView()
        bgImageView.clipsToBounds = true
        bgImageView.image = UIImage.withColor(color: UIColor.black.withAlphaComponent(0.5), size: CGSize(width: width, height: width))
        addSubview(bgImageView)
        bgImageView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        
        leftImageView = UIImageView()
        leftImageView.image = iconOfWhitePlay()
        addSubview(leftImageView)
        leftImageView.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.size.equalTo(CGSize(width: 16, height: 16))
        }
        
        let animation = LottieAnimation.named("voice_white")
        voiceAnimation = LottieAnimationView(animation: animation)
        //voiceAnimation = EPLottieAnimationView.animationNamed("voice_white.json")
        voiceAnimation.isUserInteractionEnabled = false
        voiceAnimation.loopMode = .loop
        voiceAnimation.animationSpeed = 1.4
        voiceAnimation.contentMode = .scaleAspectFit
        voiceAnimation.isHidden = true
        voiceAnimation.tintColor = .white
        addSubview(voiceAnimation)
        voiceAnimation.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.size.equalTo(CGSize(width: 16, height: 16))
        }
        
        indicator = IndicatorView(color: .white)
        indicator.size = CGSize(width: 16, height: 16)
        indicator.isHidden = true
        addSubview(indicator)
        indicator.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.size.equalTo(CGSize(width: 16, height: 16))
        }
    }
    
    // MARK: - Style(Custom) 3: Clear bg
    private func initialClearBgPlayStyle() {
        iconSize = CGSize(width: 20, height: 20)
        touchAreaInsets = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
        snp.makeConstraints { make in
            make.width.equalTo(20)
            make.height.equalTo(20)
        }
        layer.cornerRadius = 0
        clipsToBounds = true
        
        leftImageView = UIImageView()
        leftImageView.image = iconOfWhitePlay()
        addSubview(leftImageView)
        leftImageView.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.size.equalTo(CGSize(width: 16, height: 16))
        }
        
        let animation = LottieAnimation.named("voice_white")// 
        voiceAnimation = LottieAnimationView(animation: animation)
        voiceAnimation.isUserInteractionEnabled = false
        voiceAnimation.loopMode = .loop
        voiceAnimation.animationSpeed = 1.4
        voiceAnimation.contentMode = .scaleAspectFit
        voiceAnimation.isHidden = true
        voiceAnimation.tintColor = .black
        addSubview(voiceAnimation)
        voiceAnimation.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.size.equalTo(CGSize(width: 16, height: 16))
        }
        
        indicator = IndicatorView(color: .white) // .withAlphaComponent(0.5)
        indicator.size = CGSize(width: 16, height: 16)
        indicator.isHidden = true
        addSubview(indicator)
        indicator.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.size.equalTo(CGSize(width: 16, height: 16))
        }
    }
    
    private func initialVoiceThemePlay(){
        iconSize = CGSize(width: 12, height: 12)
        touchAreaInsets = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
        snp.makeConstraints { make in
            make.width.equalTo(24)
            make.height.equalTo(24)
        }
        layer.cornerRadius = 12
        backgroundColor = .c.cpvn
        clipsToBounds = true
        
        leftImageView = UIImageView()
        leftImageView.image = iconOfWhitePlay()
        addSubview(leftImageView)
        leftImageView.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.size.equalTo(CGSize(width: 12, height: 12))
        }
        
        let animation = LottieAnimation.named("voice_white")//
        voiceAnimation = LottieAnimationView(animation: animation)
        voiceAnimation.isUserInteractionEnabled = false
        voiceAnimation.loopMode = .loop
        voiceAnimation.animationSpeed = 1.4
        voiceAnimation.contentMode = .scaleAspectFit
        voiceAnimation.isHidden = true
        voiceAnimation.tintColor = .black
        addSubview(voiceAnimation)
        voiceAnimation.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.size.equalTo(CGSize(width: 12, height: 12))
        }
        
        indicator = IndicatorView(color: .white) // .withAlphaComponent(0.5)
        indicator.size = CGSize(width: 12, height: 12)
        indicator.isHidden = true
        addSubview(indicator)
        indicator.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.size.equalTo(CGSize(width: 12, height: 12))
        }
    }
    
    // MARK: - Icons
    func iconOfWhitePlay() -> UIImage? {
        return MWIconFont.image(fromIcon: .play, size: self.iconSize, color: .white)
    }
    
    func iconOfWhiteVoice() -> UIImage? {
        return MWIconFont.image(fromIcon: .voiceLive, size: self.iconSize, color: .white)
    }
    
    func blackIcon() -> UIImage? {
        return MWIconFont.image(fromIcon: .play, size: self.iconSize, color: .c.csbn)
    }
    
    // MARK: - Public Methods
    func startIndicator() {
        DispatchQueue.main.async { [weak self] in
            guard let self = self else { return }
            if self.indicator.isAnimating {
                self.leftImageView.isHidden = true
                self.voiceAnimation.isHidden = true
                return
            }
            self.indicator.startAnimating()
            self.leftImageView.isHidden = true
            self.voiceAnimation.isHidden = true
        }
    }
    
    func stopIndicator() {
        DispatchQueue.main.async { [weak self] in
            guard let self = self else { return }
            if !self.indicator.isAnimating {
                self.leftImageView.isHidden = false
                self.voiceAnimation.isHidden = true
                return
            }
            self.leftImageView.isHidden = false
            self.voiceAnimation.isHidden = true
            self.indicator.stopAnimating()
        }
    }
    
    func startAnimation() {
        DispatchQueue.main.async { [weak self] in
            guard let self = self else { return }
            if self.voiceAnimation.isAnimationPlaying {
                return
            }
            self.voiceAnimation.isHidden = false
            self.leftImageView.isHidden = true
            self.voiceAnimation.play()
        }
    }
    
    func stopAnimation() {
        DispatchQueue.main.async { [weak self] in
            guard let self = self else { return }
            if !self.voiceAnimation.isAnimationPlaying {
                return
            }
            self.voiceAnimation.stop()
            self.voiceAnimation.isHidden = true
            self.leftImageView.isHidden = false
        }
    }
    
    func reloadState(with model: SpeechModel?) {
        guard let speechModel = model else{
            reloadViews(model: model)
            return
        }
        self.path = speechModel.path
        speechModel.stateChangedBlock = { [weak self] updatedModel in
            guard let self = self, self.path == updatedModel.path else { return }
            self.reloadViews(model: updatedModel)
            self.checkState(model: updatedModel)
        }
        reloadViews(model: speechModel)
    }
    
    // MARK: - Private Methods
    private func reloadViews(model: SpeechModel?) {
        guard let audioModel = model else{
            stopIndicator()
            stopAnimation()
            return
        }
        if audioModel.loadState == .loading {
            startIndicator()
        } else {
            stopIndicator()
        }
        if audioModel.playState == .playing {
            startAnimation()
        } else {
            stopAnimation()
        }
    }
    
    private func checkState(model: SpeechModel) {
        guard model.loadState == .complete else {
            // SpeechManager.shared.stopPlay(with: model) // ❌
            return
        }
        
        switch model.playState {
        case .default:
            if model.canAutoPlay && isDisplay {
                SpeechManager.shared.startPlay(with: model)
            }
        case .complete, .failed:
            SpeechManager.shared.stopPlay(with: model)
        case .playing:
            break
        }
    }
    
    // MARK: - Deinit
    deinit {
        // 🔥 Replacing DLog with print
        print("♻️ AudioButton dealloc")
    }
}
