import Foundation
import UIKit
import CoreImage

/// Layer for drawing operations
public class DrawingLayer: ImageLayer {
    private var drawingPaths: [DrawingPath] = []
    private let renderer = UIGraphicsImageRenderer(size: .zero)

    public init(bounds: CGRect) {
        super.init(name: "Drawing", image: nil, bounds: bounds)
        self.image = createEmptyImage(size: bounds.size)
    }

    /// Add a drawing path
    public func addPath(_ path: DrawingPath) {
        drawingPaths.append(path)
        updateImage()
    }

    /// Remove the last path (for undo)
    public func removeLastPath() {
        guard !drawingPaths.isEmpty else { return }
        drawingPaths.removeLast()
        updateImage()
    }

    /// Clear all paths
    public func clearAll() {
        drawingPaths.removeAll()
        updateImage()
    }

    /// Update the layer image from drawing paths
    private func updateImage() {
        let size = bounds.size
        let renderer = UIGraphicsImageRenderer(size: size)

        let uiImage = renderer.image { context in
            let cgContext = context.cgContext

            for path in drawingPaths {
                cgContext.setStrokeColor(path.color.cgColor)
                cgContext.setLineWidth(path.width)
                cgContext.setLineCap(.round)
                cgContext.setLineJoin(.round)
                cgContext.setAlpha(path.opacity)

                if path.isEraser {
                    cgContext.setBlendMode(.clear)
                } else {
                    cgContext.setBlendMode(.normal)
                }

                if let firstPoint = path.points.first {
                    cgContext.move(to: firstPoint)
                    for point in path.points.dropFirst() {
                        cgContext.addLine(to: point)
                    }
                    cgContext.strokePath()
                }
            }
        }

        self.image = CIImage(image: uiImage)
    }

    private func createEmptyImage(size: CGSize) -> CIImage {
        let renderer = UIGraphicsImageRenderer(size: size)
        let uiImage = renderer.image { context in
            UIColor.clear.setFill()
            context.fill(CGRect(origin: .zero, size: size))
        }
        return CIImage(image: uiImage) ?? CIImage.empty()
    }
}

/// Represents a single drawing stroke
public struct DrawingPath {
    public var points: [CGPoint]
    public var color: UIColor
    public var width: CGFloat
    public var opacity: CGFloat
    public var isEraser: Bool

    public init(points: [CGPoint] = [], color: UIColor = .black, width: CGFloat = 5.0, opacity: CGFloat = 1.0, isEraser: Bool = false) {
        self.points = points
        self.color = color
        self.width = width
        self.opacity = opacity
        self.isEraser = isEraser
    }
}

/// Layer for text overlays
public class TextLayer: ImageLayer {
    public var text: String
    public var font: UIFont
    public var textColor: UIColor
    public var textAlignment: NSTextAlignment
    public var backgroundColor: UIColor?
    public var padding: UIEdgeInsets

    public init(text: String, bounds: CGRect, font: UIFont = .systemFont(ofSize: 32), color: UIColor = .white) {
        self.text = text
        self.font = font
        self.textColor = color
        self.textAlignment = .left
        self.backgroundColor = nil
        self.padding = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)

        super.init(name: "Text", image: nil, bounds: bounds)
        updateImage()
    }

    /// Update text content
    public func updateText(_ newText: String) {
        self.text = newText
        updateImage()
    }

    /// Update text font
    public func updateFont(_ newFont: UIFont) {
        self.font = newFont
        updateImage()
    }

    /// Update text color
    public func updateColor(_ newColor: UIColor) {
        self.textColor = newColor
        updateImage()
    }

    /// Update the layer image from text properties
    private func updateImage() {
        let size = bounds.size
        let renderer = UIGraphicsImageRenderer(size: size)

        let uiImage = renderer.image { context in
            let rect = CGRect(origin: .zero, size: size)

            // Draw background if set
            if let bgColor = backgroundColor {
                bgColor.setFill()
                context.fill(rect)
            }

            // Calculate text rect with padding
            let textRect = rect.inset(by: padding)

            // Draw text
            let paragraphStyle = NSMutableParagraphStyle()
            paragraphStyle.alignment = textAlignment

            let attributes: [NSAttributedString.Key: Any] = [
                .font: font,
                .foregroundColor: textColor,
                .paragraphStyle: paragraphStyle
            ]

            text.draw(in: textRect, withAttributes: attributes)
        }

        self.image = CIImage(image: uiImage)
    }
}

/// Layer for shape overlays
public class ShapeLayer: ImageLayer {
    public var shape: Shape
    public var strokeColor: UIColor
    public var fillColor: UIColor?
    public var lineWidth: CGFloat

    public init(shape: Shape, bounds: CGRect, strokeColor: UIColor = .black, fillColor: UIColor? = nil, lineWidth: CGFloat = 2.0) {
        self.shape = shape
        self.strokeColor = strokeColor
        self.fillColor = fillColor
        self.lineWidth = lineWidth

        super.init(name: "Shape", image: nil, bounds: bounds)
        updateImage()
    }

    /// Update shape properties
    public func updateShape(_ newShape: Shape) {
        self.shape = newShape
        updateImage()
    }

    private func updateImage() {
        let size = bounds.size
        let renderer = UIGraphicsImageRenderer(size: size)

        let uiImage = renderer.image { context in
            let cgContext = context.cgContext

            cgContext.setStrokeColor(strokeColor.cgColor)
            cgContext.setLineWidth(lineWidth)

            if let fill = fillColor {
                cgContext.setFillColor(fill.cgColor)
            }

            switch shape {
            case .rectangle(let rect):
                if fillColor != nil {
                    cgContext.fill(rect)
                }
                cgContext.stroke(rect)

            case .circle(let center, let radius):
                let rect = CGRect(x: center.x - radius, y: center.y - radius, width: radius * 2, height: radius * 2)
                if fillColor != nil {
                    cgContext.fillEllipse(in: rect)
                }
                cgContext.strokeEllipse(in: rect)

            case .line(let start, let end):
                cgContext.move(to: start)
                cgContext.addLine(to: end)
                cgContext.strokePath()

            case .arrow(let start, let end):
                drawArrow(context: cgContext, from: start, to: end)
            }
        }

        self.image = CIImage(image: uiImage)
    }

    private func drawArrow(context: CGContext, from start: CGPoint, to end: CGPoint) {
        context.move(to: start)
        context.addLine(to: end)
        context.strokePath()

        // Draw arrowhead
        let arrowLength: CGFloat = 20
        let arrowAngle: CGFloat = .pi / 6

        let angle = atan2(end.y - start.y, end.x - start.x)

        let point1 = CGPoint(
            x: end.x - arrowLength * cos(angle - arrowAngle),
            y: end.y - arrowLength * sin(angle - arrowAngle)
        )
        let point2 = CGPoint(
            x: end.x - arrowLength * cos(angle + arrowAngle),
            y: end.y - arrowLength * sin(angle + arrowAngle)
        )

        context.move(to: end)
        context.addLine(to: point1)
        context.move(to: end)
        context.addLine(to: point2)
        context.strokePath()
    }

    public enum Shape {
        case rectangle(CGRect)
        case circle(center: CGPoint, radius: CGFloat)
        case line(start: CGPoint, end: CGPoint)
        case arrow(start: CGPoint, end: CGPoint)
    }
}

/// Layer for sticker/image overlays
public class StickerLayer: ImageLayer {
    public var stickerImage: UIImage

    public init(sticker: UIImage, bounds: CGRect) {
        self.stickerImage = sticker
        super.init(name: "Sticker", image: CIImage(image: sticker), bounds: bounds)
    }

    /// Update sticker image
    public func updateSticker(_ newSticker: UIImage) {
        self.stickerImage = newSticker
        self.image = CIImage(image: newSticker)
    }
}
