import Foundation
import UIKit
import CoreImage

/// Represents a single layer in the image editor
public class ImageLayer {
    public let id: UUID
    public var name: String
    public var image: CIImage?
    public var opacity: Float = 1.0
    public var isVisible: Bool = true
    public var blendMode: BlendMode = .normal
    public var transform: CGAffineTransform = .identity
    public var bounds: CGRect

    public init(id: UUID = UUID(), name: String, image: CIImage?, bounds: CGRect) {
        self.id = id
        self.name = name
        self.image = image
        self.bounds = bounds
    }

    /// Blend modes supported by the layer system
    public enum BlendMode: String, CaseIterable {
        case normal
        case multiply
        case screen
        case overlay
        case darken
        case lighten
        case colorDodge
        case colorBurn
        case softLight
        case hardLight
        case difference
        case exclusion
        case hue
        case saturation
        case color
        case luminosity

        var ciFilterName: String? {
            switch self {
            case .normal: return nil
            case .multiply: return "CIMultiplyBlendMode"
            case .screen: return "CIScreenBlendMode"
            case .overlay: return "CIOverlayBlendMode"
            case .darken: return "CIDarkenBlendMode"
            case .lighten: return "CILightenBlendMode"
            case .colorDodge: return "CIColorDodgeBlendMode"
            case .colorBurn: return "CIColorBurnBlendMode"
            case .softLight: return "CISoftLightBlendMode"
            case .hardLight: return "CIHardLightBlendMode"
            case .difference: return "CIDifferenceBlendMode"
            case .exclusion: return "CIExclusionBlendMode"
            case .hue: return "CIHueBlendMode"
            case .saturation: return "CISaturationBlendMode"
            case .color: return "CIColorBlendMode"
            case .luminosity: return "CILuminosityBlendMode"
            }
        }
    }

    /// Creates a copy of the layer
    public func copy() -> ImageLayer {
        let newLayer = ImageLayer(id: UUID(), name: name, image: image, bounds: bounds)
        newLayer.opacity = opacity
        newLayer.isVisible = isVisible
        newLayer.blendMode = blendMode
        newLayer.transform = transform
        return newLayer
    }
}

/// Manages multiple layers in the editor
public class LayerManager {
    private(set) public var layers: [ImageLayer] = []
    private let ciContext: CIContext

    public init(ciContext: CIContext) {
        self.ciContext = ciContext
    }

    /// Adds a new layer
    public func addLayer(_ layer: ImageLayer, at index: Int? = nil) {
        if let index = index {
            layers.insert(layer, at: min(index, layers.count))
        } else {
            layers.append(layer)
        }
    }

    /// Removes a layer by ID
    public func removeLayer(id: UUID) {
        layers.removeAll { $0.id == id }
    }

    /// Moves a layer to a new index
    public func moveLayer(id: UUID, to newIndex: Int) {
        guard let currentIndex = layers.firstIndex(where: { $0.id == id }) else { return }
        let layer = layers.remove(at: currentIndex)
        layers.insert(layer, at: min(newIndex, layers.count))
    }

    /// Gets a layer by ID
    public func layer(withId id: UUID) -> ImageLayer? {
        return layers.first { $0.id == id }
    }

    /// Composites all visible layers into a single image
    public func composite() -> CIImage? {
        guard !layers.isEmpty else { return nil }

        var compositeImage: CIImage?

        for layer in layers where layer.isVisible {
            guard var layerImage = layer.image else { continue }

            // Apply transform
            if layer.transform != .identity {
                layerImage = layerImage.transformed(by: layer.transform)
            }

            // Apply opacity
            if layer.opacity < 1.0 {
                let colorMatrix = CIFilter(name: "CIColorMatrix")
                colorMatrix?.setValue(layerImage, forKey: kCIInputImageKey)
                colorMatrix?.setValue(CIVector(x: 0, y: 0, z: 0, w: CGFloat(layer.opacity)), forKey: "inputAVector")
                if let output = colorMatrix?.outputImage {
                    layerImage = output
                }
            }

            // Composite with blend mode
            if let composite = compositeImage {
                compositeImage = blend(background: composite, foreground: layerImage, mode: layer.blendMode)
            } else {
                compositeImage = layerImage
            }
        }

        return compositeImage
    }

    /// Blends two images with the specified blend mode
    private func blend(background: CIImage, foreground: CIImage, mode: ImageLayer.BlendMode) -> CIImage {
        guard let filterName = mode.ciFilterName,
              let filter = CIFilter(name: filterName) else {
            // Normal blend mode
            return foreground.composited(over: background)
        }

        filter.setValue(background, forKey: kCIInputBackgroundImageKey)
        filter.setValue(foreground, forKey: kCIInputImageKey)

        return filter.outputImage ?? background
    }

    /// Creates a snapshot of current layer state
    public func snapshot() -> [ImageLayer] {
        return layers.map { $0.copy() }
    }

    /// Restores layer state from snapshot
    public func restore(from snapshot: [ImageLayer]) {
        layers = snapshot.map { $0.copy() }
    }
}
