import SwiftUI
import UIKit

/// Telegram-parity Dynamic Island blur effect.
/// Replicates DynamicIslandBlurNode.swift from Telegram iOS:
/// - UIVisualEffectView(.dark) with UIViewPropertyAnimator for progressive blur
/// - Black fade overlay with alpha formula
/// - Radial gradient for edge feathering
struct DynamicIslandBlurView: UIViewRepresentable {
    let progress: CGFloat

    func makeUIView(context: Context) -> DynamicIslandBlurUIView {
        DynamicIslandBlurUIView()
    }

    func updateUIView(_ uiView: DynamicIslandBlurUIView, context: Context) {
        uiView.update(progress)
    }
}

final class DynamicIslandBlurUIView: UIView {
    private var effectView: UIVisualEffectView?
    private let fadeView = UIView()
    private let gradientView = UIImageView()
    private var animator: UIViewPropertyAnimator?

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

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

    private func setup() {
        isUserInteractionEnabled = false
        clipsToBounds = true

        // Blur effect view (Telegram: effectView with nil initial effect)
        let effectView = UIVisualEffectView(effect: nil)
        effectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        self.effectView = effectView
        addSubview(effectView)

        // Radial gradient (Telegram: 100×100, center offset +38, radius 90)
        gradientView.image = Self.makeGradientImage()
        gradientView.contentMode = .center
        gradientView.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin]
        addSubview(gradientView)

        // Fade overlay (Telegram: black, alpha driven by formula)
        fadeView.backgroundColor = .black
        fadeView.alpha = 0
        fadeView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        addSubview(fadeView)
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        effectView?.frame = bounds
        fadeView.frame = bounds

        let gradientSize = CGSize(width: 100, height: 100)
        gradientView.frame = CGRect(
            x: (bounds.width - gradientSize.width) / 2,
            y: 0,
            width: gradientSize.width,
            height: gradientSize.height
        )
    }

    func update(_ value: CGFloat) {
        // Telegram formula: fadeAlpha = min(1.0, max(0.0, -0.25 + value * 1.55))
        let fadeAlpha = min(1.0, max(0.0, -0.25 + value * 1.55))

        if value > 0.0 {
            var adjustedValue = value
            let prepared = prepare()
            if adjustedValue > 0.99 && prepared {
                adjustedValue = 0.99
            }
            // Telegram formula: fractionComplete = max(0.0, -0.1 + value * 1.1)
            animator?.fractionComplete = max(0.0, -0.1 + adjustedValue * 1.1)
        } else {
            animator?.stopAnimation(true)
            animator = nil
            effectView?.effect = nil
        }

        fadeView.alpha = fadeAlpha
    }

    private func prepare() -> Bool {
        guard animator == nil else { return false }

        let anim = UIViewPropertyAnimator(duration: 1.0, curve: .linear)
        animator = anim
        effectView?.effect = nil
        anim.addAnimations { [weak self] in
            self?.effectView?.effect = UIBlurEffect(style: .dark)
        }
        return true
    }

    deinit {
        animator?.stopAnimation(true)
    }

    // Telegram: radial gradient 100×100, center (50, 88), radius 90
    // Colors: transparent → transparent (0.87) → black (1.0)
    private static func makeGradientImage() -> UIImage? {
        let size = CGSize(width: 100, height: 100)
        UIGraphicsBeginImageContextWithOptions(size, false, 0)
        guard let ctx = UIGraphicsGetCurrentContext() else { return nil }

        let colorSpace = CGColorSpaceCreateDeviceRGB()
        var locations: [CGFloat] = [0.0, 0.87, 1.0]
        let colors: [CGColor] = [
            UIColor(white: 0, alpha: 0).cgColor,
            UIColor(white: 0, alpha: 0).cgColor,
            UIColor(white: 0, alpha: 1).cgColor,
        ]
        guard let gradient = CGGradient(
            colorsSpace: colorSpace,
            colors: colors as CFArray,
            locations: &locations
        ) else {
            UIGraphicsEndImageContext()
            return nil
        }

        let center = CGPoint(x: size.width / 2, y: size.height / 2 + 38)
        ctx.drawRadialGradient(
            gradient,
            startCenter: center,
            startRadius: 0,
            endCenter: center,
            endRadius: 90,
            options: .drawsAfterEndLocation
        )

        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}
