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)
//
// Exact port of Telegram iOS LegacyGlassView + GlassBackgroundView foreground.
// iOS < 26: CABackdropLayer with gaussianBlur radius 2.0 + dark foreground overlay.
// 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()
    private let foregroundLayer = CALayer()

    // iOS 26+ native glass
    private var nativeGlassView: UIVisualEffectView?

    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

        if #available(iOS 26.0, *) {
            setupNativeGlass()
        } else {
            setupLegacyGlass()
        }
    }

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

    // MARK: - iOS 26+ (native UIGlassEffect)

    @available(iOS 26.0, *)
    private func setupNativeGlass() {
        let effect = UIGlassEffect(style: .regular)
        effect.isInteractive = false
        // Telegram dark mode tint: UIColor(white: 1.0, alpha: 0.025)
        effect.tintColor = UIColor(white: 1.0, alpha: 0.025)
        let glassView = UIVisualEffectView(effect: effect)
        glassView.clipsToBounds = true
        glassView.layer.cornerCurve = .continuous
        // Set initial corner radius — will be updated in layoutSubviews.
        glassView.layer.cornerRadius = 22
        glassView.isUserInteractionEnabled = false
        addSubview(glassView)
        nativeGlassView = glassView
    }

    // MARK: - iOS < 26 (CABackdropLayer — Telegram LegacyGlassView)

    private func setupLegacyGlass() {
        // Clipping container — holds backdrop + foreground, clips to pill shape.
        // Border is added to main layer OUTSIDE the clip so it's fully visible.
        clippingContainer.masksToBounds = true
        clippingContainer.cornerCurve = .continuous
        layer.addSublayer(clippingContainer)

        // 1. CABackdropLayer — blurs content behind this view
        if let backdrop = Self.createBackdropLayer() {
            backdrop.rasterizationScale = 1.0
            Self.setBackdropScale(backdrop, scale: 1.0)

            // gaussianBlur filter with radius 2.0 (Telegram .normal style)
            if let blurFilter = Self.makeBlurFilter() {
                blurFilter.setValue(2.0 as NSNumber, forKey: "inputRadius")
                backdrop.filters = [blurFilter]
            }

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

        // 2. Foreground — dark semi-transparent fill
        foregroundLayer.backgroundColor = UIColor(white: 0.11, alpha: 0.85).cgColor
        clippingContainer.addSublayer(foregroundLayer)

        // 3. Border — on main layer via CALayer border properties.
        // Using layer.borderWidth + cornerCurve ensures the border follows
        // the same .continuous curve as the clipping container fill.
        layer.borderWidth = 0.5
        layer.borderColor = UIColor(red: 0x38/255.0, green: 0x38/255.0, blue: 0x38/255.0, alpha: 1.0).cgColor
        layer.cornerCurve = .continuous
    }

    // 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
        }
        if #available(iOS 26.0, *), let glassView = nativeGlassView {
            glassView.layer.cornerRadius = radius
        } else {
            clippingContainer.cornerRadius = radius
            layer.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 {
            // Cap at half-height to guarantee capsule shape when radius >= height/2.
            cornerRadius = min(fixed, bounds.height / 2)
        } else if isCircle {
            cornerRadius = min(bounds.width, bounds.height) / 2
        } else {
            cornerRadius = bounds.height / 2
        }

        if #available(iOS 26.0, *), let glassView = nativeGlassView {
            glassView.frame = bounds
            // Use cornerRadius directly — simpler and works in current iOS 26 betas.
            // CAShapeLayer mask was unreliable with UIGlassEffect in some beta versions.
            glassView.layer.cornerRadius = cornerRadius
            return
        }

        // Legacy layout — clippingContainer.masksToBounds clips all children,
        // so foregroundLayer needs no cornerRadius (avoids double-rounding artifacts).
        clippingContainer.frame = bounds
        clippingContainer.cornerRadius = cornerRadius
        backdropLayer?.frame = bounds
        foregroundLayer.frame = bounds

        // Border follows .continuous curve via main layer's cornerRadius.
        // clipsToBounds is false, so this only affects visual border — not child clipping.
        layer.cornerRadius = cornerRadius
    }

    // MARK: - Shadow (drawn as separate image — Telegram parity)

    /// 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? {
        let inset: CGFloat = 32
        let innerInset: CGFloat = 0.5
        let diameter = cornerRadius * 2
        let totalSize = CGSize(width: inset * 2 + diameter, height: inset * 2 + diameter)

        let image = UIGraphicsImageRenderer(size: totalSize).image { ctx in
            let context = ctx.cgContext
            context.clear(CGRect(origin: .zero, size: totalSize))

            context.setFillColor(UIColor.black.cgColor)
            context.setShadow(
                offset: CGSize(width: 0, height: 1),
                blur: 40.0,
                color: UIColor(white: 0.0, alpha: 0.04).cgColor
            )
            let ellipseRect = CGRect(
                x: inset + innerInset,
                y: inset + innerInset,
                width: totalSize.width - (inset + innerInset) * 2,
                height: totalSize.height - (inset + innerInset) * 2
            )
            context.fillEllipse(in: ellipseRect)

            // Punch out the center (shadow only, no fill)
            context.setFillColor(UIColor.clear.cgColor)
            context.setBlendMode(.copy)
            context.fillEllipse(in: ellipseRect)
        }
        return image.stretchableImage(
            withLeftCapWidth: Int(inset + cornerRadius),
            topCapHeight: Int(inset + cornerRadius)
        )
    }

    // MARK: - Private API Helpers (same approach as Telegram)

    private static func createBackdropLayer() -> CALayer? {
        let className = ["CA", "Backdrop", "Layer"].joined()
        guard let cls = NSClassFromString(className) as? CALayer.Type else { return nil }
        return cls.init()
    }

    private static func setBackdropScale(_ layer: CALayer, scale: Double) {
        let sel = NSSelectorFromString("setScale:")
        guard layer.responds(to: sel) else { return }
        layer.perform(sel, with: NSNumber(value: scale))
    }

    private static func makeBlurFilter() -> NSObject? {
        let className = ["CA", "Filter"].joined()
        guard let cls = NSClassFromString(className) as? NSObject.Type else { return nil }
        let sel = NSSelectorFromString("filterWithName:")
        guard cls.responds(to: sel) else { return nil }
        return cls.perform(sel, with: "gaussianBlur")?.takeUnretainedValue() as? NSObject
    }
}
