import SwiftUI
import CoreImage

// MARK: - Animated Call Gradient Background

/// Full-screen animated gradient tied to the peer's avatar color or photo.
/// Uses Canvas + TimelineView for GPU-composited rendering at 30fps.
/// When `peerAvatar` is provided, extracts dominant color from the photo.
struct CallGradientBackground: View {
    let colorIndex: Int
    private let palette: CallGradientPalette
    private let baseColor = Color(hex: 0x0D0D14)

    init(colorIndex: Int, peerAvatar: UIImage? = nil) {
        self.colorIndex = colorIndex
        if let avatar = peerAvatar,
           let dominant = Self.dominantColor(from: avatar) {
            self.palette = CallGradientPalette(baseColor: dominant)
        } else {
            self.palette = CallGradientPalette(colorIndex: colorIndex)
        }
    }

    // MARK: - Dominant Color Extraction

    private static let ciContext = CIContext(options: [.workingColorSpace: kCFNull as Any])

    private static func dominantColor(from image: UIImage) -> UIColor? {
        guard let ciImage = CIImage(image: image) else { return nil }
        let extent = ciImage.extent
        guard let filter = CIFilter(name: "CIAreaAverage", parameters: [
            kCIInputImageKey: ciImage,
            kCIInputExtentKey: CIVector(cgRect: extent)
        ]),
        let outputImage = filter.outputImage else { return nil }

        var bitmap = [UInt8](repeating: 0, count: 4)
        ciContext.render(outputImage, toBitmap: &bitmap, rowBytes: 4,
                         bounds: CGRect(x: 0, y: 0, width: 1, height: 1),
                         format: .RGBA8, colorSpace: nil)
        return UIColor(red: CGFloat(bitmap[0]) / 255.0, green: CGFloat(bitmap[1]) / 255.0,
                       blue: CGFloat(bitmap[2]) / 255.0, alpha: 1.0)
    }

    var body: some View {
        TimelineView(.periodic(from: .now, by: 1.0 / 30.0)) { timeline in
            let t = timeline.date.timeIntervalSince1970
            Canvas { context, size in
                // Solid dark base
                context.fill(
                    Path(CGRect(origin: .zero, size: size)),
                    with: .color(baseColor)
                )

                let w = size.width
                let h = size.height

                // 3 animated radial gradient blobs
                drawBlob(
                    context: context,
                    center: CGPoint(
                        x: w * (0.5 + 0.3 * sin(t * 0.23)),
                        y: h * (0.3 + 0.2 * sin(t * 0.19 + 1.0))
                    ),
                    radius: max(w, h) * 0.7,
                    color: palette.primary,
                    opacity: 0.55
                )

                drawBlob(
                    context: context,
                    center: CGPoint(
                        x: w * (0.5 + 0.35 * sin(t * 0.17 + 2.0)),
                        y: h * (0.65 + 0.25 * sin(t * 0.21 + 3.5))
                    ),
                    radius: max(w, h) * 0.65,
                    color: palette.shifted,
                    opacity: 0.45
                )

                drawBlob(
                    context: context,
                    center: CGPoint(
                        x: w * (0.5 + 0.2 * sin(t * 0.29 + 4.0)),
                        y: h * (0.45 + 0.25 * sin(t * 0.15 + 5.5))
                    ),
                    radius: max(w, h) * 0.6,
                    color: palette.dark,
                    opacity: 0.5
                )
            }
        }
        .ignoresSafeArea()
    }

    private func drawBlob(
        context: GraphicsContext,
        center: CGPoint,
        radius: CGFloat,
        color: Color,
        opacity: Double
    ) {
        let rect = CGRect(
            x: center.x - radius,
            y: center.y - radius,
            width: radius * 2,
            height: radius * 2
        )
        let gradient = Gradient(colors: [
            color.opacity(opacity),
            color.opacity(opacity * 0.4),
            .clear
        ])
        context.fill(
            Path(ellipseIn: rect),
            with: .radialGradient(
                gradient,
                center: center,
                startRadius: 0,
                endRadius: radius
            )
        )
    }
}

// MARK: - Gradient Palette

/// Derives 3 colors from the peer's avatar color index.
private struct CallGradientPalette {
    let primary: Color
    let dark: Color
    let shifted: Color

    init(colorIndex: Int) {
        let colors = RosettaColors.avatarColors
        let idx = abs(colorIndex) % colors.count
        let tint = colors[idx].tint

        let uiColor = UIColor(tint)
        var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
        uiColor.getRed(&r, green: &g, blue: &b, alpha: &a)

        primary = tint
        dark = Color(red: r * 0.27, green: g * 0.27, blue: b * 0.27)

        // Hue-shift +25 degrees, darken to 70%
        var h: CGFloat = 0, s: CGFloat = 0, br: CGFloat = 0
        uiColor.getHue(&h, saturation: &s, brightness: &br, alpha: &a)
        let shiftedHue = (h + 25.0 / 360.0).truncatingRemainder(dividingBy: 1.0)
        shifted = Color(hue: shiftedHue, saturation: s, brightness: br * 0.7)
    }

    /// Palette derived from avatar photo's dominant color.
    /// Boosts saturation since CIAreaAverage returns muted averages.
    init(baseColor: UIColor) {
        var h: CGFloat = 0, s: CGFloat = 0, br: CGFloat = 0, a: CGFloat = 0
        baseColor.getHue(&h, saturation: &s, brightness: &br, alpha: &a)

        let sat = min(s * 1.4, 1.0)
        let bri = min(br * 1.1, 1.0)
        let boosted = UIColor(hue: h, saturation: sat, brightness: bri, alpha: 1)
        var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0
        boosted.getRed(&r, green: &g, blue: &b, alpha: &a)

        primary = Color(red: r, green: g, blue: b)
        dark = Color(red: r * 0.27, green: g * 0.27, blue: b * 0.27)
        let shiftedHue = (h + 25.0 / 360.0).truncatingRemainder(dividingBy: 1.0)
        shifted = Color(hue: shiftedHue, saturation: sat, brightness: bri * 0.7)
    }
}
