import SwiftUI
import UIKit

// MARK: - Environment Key: Glass Active

/// When false, TelegramGlassUIView removes its CABackdropLayer from the
/// layer tree, stopping real-time blur (zero GPU cost). When true, the
/// backdrop layer is re-inserted and blur resumes.
///
/// Usage: set `.environment(\.telegramGlassActive, false)` on views whose
/// glass effects should be frozen (e.g. hidden tabs in a ZStack pager).
private struct TelegramGlassActiveKey: EnvironmentKey {
    static let defaultValue: Bool = true
}

extension EnvironmentValues {
    var telegramGlassActive: Bool {
        get { self[TelegramGlassActiveKey.self] }
        set { self[TelegramGlassActiveKey.self] = newValue }
    }
}

// MARK: - Telegram Glass (CABackdropLayer + CAFilter + Mesh + Foreground Image)
//
// Exact port of Telegram iOS LegacyGlassView + GlassBackgroundView foreground.
// iOS < 26: CABackdropLayer with gaussianBlur + colorMatrix + mesh displacement
//           + generated foreground image with shadows, gradient border, blend modes.
// iOS 26+: native UIGlassEffect(style: .regular).

/// SwiftUI wrapper for Telegram-style glass background.
/// Capsule shape with proper corner radius.
struct TelegramGlassCapsule: UIViewRepresentable {
    func makeUIView(context: Context) -> TelegramGlassUIView {
        let view = TelegramGlassUIView(frame: .zero)
        view.backgroundColor = .clear
        return view
    }

    func updateUIView(_ uiView: TelegramGlassUIView, context: Context) {
        uiView.isFrozen = !context.environment.telegramGlassActive
        uiView.updateGlass()
    }
}

/// SwiftUI wrapper for Telegram-style glass circle.
struct TelegramGlassCircle: UIViewRepresentable {
    func makeUIView(context: Context) -> TelegramGlassUIView {
        let view = TelegramGlassUIView(frame: .zero)
        view.backgroundColor = .clear
        view.isCircle = true
        return view
    }

    func updateUIView(_ uiView: TelegramGlassUIView, context: Context) {
        uiView.isFrozen = !context.environment.telegramGlassActive
        uiView.updateGlass()
    }
}

/// SwiftUI wrapper for Telegram-style glass with custom corner radius.
struct TelegramGlassRoundedRect: UIViewRepresentable {
    let cornerRadius: CGFloat

    func makeUIView(context: Context) -> TelegramGlassUIView {
        let view = TelegramGlassUIView(frame: .zero)
        view.backgroundColor = .clear
        view.fixedCornerRadius = cornerRadius
        return view
    }

    func updateUIView(_ uiView: TelegramGlassUIView, context: Context) {
        uiView.isFrozen = !context.environment.telegramGlassActive
        uiView.fixedCornerRadius = cornerRadius
        uiView.applyCornerRadius()
        uiView.updateGlass()
    }
}

// MARK: - UIKit Implementation

final class TelegramGlassUIView: UIView {
    var isCircle = false
    /// When set, overrides auto-calculated corner radius (height/2 for capsule, min/2 for circle).
    var fixedCornerRadius: CGFloat?

    /// When true, the CABackdropLayer is removed from the layer tree,
    /// stopping real-time blur capture. Set to true for views inside
    /// hidden tabs to eliminate GPU work from invisible glass effects.
    var isFrozen: Bool = false {
        didSet {
            guard isFrozen != oldValue else { return }
            if isFrozen {
                backdropLayer?.removeFromSuperlayer()
            } else if let backdrop = backdropLayer, backdrop.superlayer == nil {
                clippingContainer.insertSublayer(backdrop, at: 0)
            }
        }
    }

    // Layers
    private var backdropLayer: CALayer?
    private let clippingContainer = CALayer()

    // Foreground + Shadow image views (legacy glass)
    private var foregroundImageView: UIImageView?
    private var shadowImageView: UIImageView?

    // Track params for image regeneration
    private var lastImageCornerRadius: CGFloat = -1
    private var lastImageIsDark: Bool?

    private static let shadowInset: CGFloat = 32.0

    override init(frame: CGRect) {
        super.init(frame: frame)
        clipsToBounds = false
        // CRITICAL: disable user interaction so glass background never intercepts
        // touches from SwiftUI Buttons that use this view as .background.
        isUserInteractionEnabled = false

        setupLegacyGlass()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    // MARK: - Glass (CABackdropLayer + ColorMatrix + Mesh — Telegram parity)

    private func setupLegacyGlass() {
        // Shadow image view — positioned behind glass with negative inset
        let shadow = UIImageView()
        shadow.isUserInteractionEnabled = false
        addSubview(shadow)
        shadowImageView = shadow

        // Clipping container — holds backdrop, clips to pill shape.
        // Telegram uses .circular cornerCurve for LegacyGlassView.
        clippingContainer.masksToBounds = true
        clippingContainer.cornerCurve = .circular
        layer.addSublayer(clippingContainer)

        // 1. CABackdropLayer — blurs + tones content behind this view
        if let backdrop = BackdropLayerHelper.createBackdropLayer() {
            backdrop.delegate = BackdropLayerDelegate.shared
            backdrop.rasterizationScale = 1.0
            BackdropLayerHelper.setScale(backdrop, scale: 1.0)

            // Blur + Color Matrix filters (Telegram .normal style)
            if let blurFilter = CALayer.blurFilter(),
               let colorMatrixFilter = CALayer.colorMatrixFilter() {
                blurFilter.setValue(2.0 as NSNumber, forKey: "inputRadius")

                var matrix: [Float32] = [
                    2.6705, -1.1087999, -0.1117, 0.0, 0.049999997,
                    -0.3295, 1.8914, -0.111899994, 0.0, 0.049999997,
                    -0.3297, -1.1084, 2.8881, 0.0, 0.049999997,
                    0.0, 0.0, 0.0, 1.0, 0.0
                ]
                colorMatrixFilter.setValue(
                    NSValue(bytes: &matrix, objCType: "{CAColorMatrix=ffffffffffffffffffff}"),
                    forKey: "inputColorMatrix"
                )
                colorMatrixFilter.setValue(true as NSNumber, forKey: "inputBackdropAware")

                backdrop.filters = [colorMatrixFilter, blurFilter]
            }

            clippingContainer.addSublayer(backdrop)
            self.backdropLayer = backdrop
        }

        // 2. Foreground image — generated overlay with fill, shadows, gradient border
        let fg = UIImageView()
        fg.isUserInteractionEnabled = false
        addSubview(fg)
        foregroundImageView = fg
    }

    // MARK: - Layout

    func updateGlass() {
        setNeedsLayout()
    }

    /// Directly applies current fixedCornerRadius to all layers without waiting for layout.
    /// Call when cornerRadius changes but bounds may not — ensures immediate visual update.
    func applyCornerRadius() {
        let bounds = bounds
        guard bounds.width > 0, bounds.height > 0 else { return }
        let radius: CGFloat
        if let fixed = fixedCornerRadius {
            radius = min(fixed, bounds.height / 2)
        } else if isCircle {
            radius = min(bounds.width, bounds.height) / 2
        } else {
            radius = bounds.height / 2
        }
        clippingContainer.cornerRadius = radius
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        let bounds = bounds
        guard bounds.width > 0, bounds.height > 0 else { return }

        let cornerRadius: CGFloat
        if let fixed = fixedCornerRadius {
            cornerRadius = min(fixed, bounds.height / 2)
        } else if isCircle {
            cornerRadius = min(bounds.width, bounds.height) / 2
        } else {
            cornerRadius = bounds.height / 2
        }

        // Layout
        clippingContainer.frame = bounds
        clippingContainer.cornerRadius = cornerRadius
        backdropLayer?.frame = bounds

        // Shadow image view — extends beyond bounds
        let si = Self.shadowInset
        shadowImageView?.frame = bounds.insetBy(dx: -si, dy: -si)

        // Foreground image view — same as shadow (image includes inset)
        foregroundImageView?.frame = bounds.insetBy(dx: -si, dy: -si)

        // Apply mesh displacement (iOS 17+, capable devices)
        if #available(iOS 17.0, *), DeviceCapability.isGraphicallyCapable {
            let size = CGSize(width: max(1.0, bounds.width), height: max(1.0, bounds.height))
            let cr = min(min(size.width, size.height) * 0.5, cornerRadius)
            let displacementMagnitudePoints: CGFloat = 20.0
            let displacementMagnitudeU = displacementMagnitudePoints / size.width
            let displacementMagnitudeV = displacementMagnitudePoints / size.height

            let mesh = generateGlassMesh(
                size: size,
                cornerRadius: cr,
                edgeDistance: min(12.0, cr),
                displacementMagnitudeU: displacementMagnitudeU,
                displacementMagnitudeV: displacementMagnitudeV,
                cornerResolution: 12,
                outerEdgeDistance: 2.0,
                bezier: DisplacementBezier(
                    x1: 0.816137566137566,
                    y1: 0.20502645502645533,
                    x2: 0.5806878306878306,
                    y2: 0.873015873015873
                )
            )

            if let meshValue = mesh.makeValue() {
                backdropLayer?.setValue(meshValue, forKey: "meshTransform")
            }
        }

        // Regenerate foreground/shadow images if needed
        regenerateGlassImages(cornerRadius: cornerRadius)
    }

    // MARK: - Image Generation

    private func regenerateGlassImages(cornerRadius: CGFloat) {
        let isDark = traitCollection.userInterfaceStyle == .dark

        // Skip if params unchanged
        if cornerRadius == lastImageCornerRadius && isDark == lastImageIsDark {
            return
        }
        lastImageCornerRadius = cornerRadius
        lastImageIsDark = isDark

        let inset = Self.shadowInset

        // Fill color (Telegram parity)
        let fillColor: UIColor
        if isDark {
            fillColor = UIColor(white: 1.0, alpha: 1.0).mixedWith(.black, alpha: 1.0 - 0.11).withAlphaComponent(0.85)
        } else {
            fillColor = UIColor(white: 1.0, alpha: 0.7)
        }

        // Foreground image
        let fgImage = GlassImageGeneration.generateLegacyGlassImage(
            size: CGSize(width: cornerRadius * 2, height: cornerRadius * 2),
            inset: inset,
            borderWidthFactor: 1.0,
            isDark: isDark,
            fillColor: fillColor
        )
        foregroundImageView?.image = fgImage

        // Shadow image
        shadowImageView?.image = GlassImageGeneration.generateShadowImage(cornerRadius: cornerRadius)
    }

    // MARK: - Adaptive Colors for Legacy Glass

    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)
        guard traitCollection.userInterfaceStyle != previousTraitCollection?.userInterfaceStyle else { return }
        // Force image regeneration on theme change
        lastImageIsDark = nil
        setNeedsLayout()
    }

    override func didMoveToWindow() {
        super.didMoveToWindow()
        // Resolve images once view is in a window and has valid traitCollection
        // This implementation always uses legacy glass, so refresh only when backdrop exists.
        if backdropLayer != nil {
            lastImageIsDark = nil
            setNeedsLayout()
        }
    }

    // MARK: - Shadow (static helper — kept for external callers)

    /// Call from parent to add Telegram-exact shadow.
    /// Telegram: blur 40, color black 4%, offset (0,1), inset 32pt.
    static func makeShadowImage(cornerRadius: CGFloat) -> UIImage? {
        return GlassImageGeneration.generateShadowImage(cornerRadius: cornerRadius)
    }
}
