import UIKit
import CoreImage

/// Interactive view for displaying and editing images
public class ImageEditorView: UIView {
    // MARK: - Properties

    public weak var delegate: ImageEditorViewDelegate?

    public var engine: ImageEditorEngine
    private let imageView: UIImageView
    private let scrollView: UIScrollView

    private var currentDrawingPath: DrawingPath?
    private var activeDrawingLayer: DrawingLayer?

    public var drawingEnabled: Bool = false {
        didSet {
            isUserInteractionEnabled = drawingEnabled
        }
    }

    public var drawingBrushSize: CGFloat = 5.0
    public var drawingColor: UIColor = .black
    public var drawingOpacity: CGFloat = 1.0
    public var isEraserMode: Bool = false

    // MARK: - Initialization

    public init(frame: CGRect, config: ImageEditorConfig = ImageEditorConfig()) {
        self.engine = ImageEditorEngine(config: config)
        self.scrollView = UIScrollView(frame: frame)
        self.imageView = UIImageView()

        super.init(frame: frame)

        setupUI()
        setupGestures()
    }

    required init?(coder: NSCoder) {
        self.engine = ImageEditorEngine()
        self.scrollView = UIScrollView()
        self.imageView = UIImageView()

        super.init(coder: coder)

        setupUI()
        setupGestures()
    }

    // MARK: - Setup

    private func setupUI() {
        backgroundColor = .black

        // Setup scroll view
        scrollView.frame = bounds
        scrollView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        scrollView.delegate = self
        scrollView.minimumZoomScale = 0.5
        scrollView.maximumZoomScale = 3.0
        scrollView.showsHorizontalScrollIndicator = false
        scrollView.showsVerticalScrollIndicator = false
        addSubview(scrollView)

        // Setup image view
        imageView.contentMode = .scaleAspectFit
        imageView.isUserInteractionEnabled = true
        scrollView.addSubview(imageView)
    }

    private func setupGestures() {
        // Pan gesture for drawing
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
        panGesture.maximumNumberOfTouches = 1
        addGestureRecognizer(panGesture)

        // Pinch gesture for zooming (handled by scroll view)
        let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(handlePinch(_:)))
        addGestureRecognizer(pinchGesture)

        // Rotation gesture
        let rotationGesture = UIRotationGestureRecognizer(target: self, action: #selector(handleRotation(_:)))
        addGestureRecognizer(rotationGesture)
    }

    // MARK: - Public Methods

    /// Load an image from URL
    public func loadImage(from url: URL) {
        do {
            let image = try engine.loadImage(from: url)
            displayImage(image)
            delegate?.imageEditorView(self, didLoadImage: image)
        } catch {
            delegate?.imageEditorView(self, didFailWithError: error)
        }
    }

    /// Load a UIImage
    public func loadImage(_ image: UIImage) {
        engine.loadImage(image)
        displayImage(image)
        delegate?.imageEditorView(self, didLoadImage: image)
    }

    /// Apply adjustments
    public func applyAdjustments(_ adjustments: ImageAdjustments) {
        let image = engine.applyAdjustments(adjustments)
        displayImage(image)
        delegate?.imageEditorView(self, didUpdateImage: image)
    }

    /// Apply a filter preset
    public func applyFilter(_ preset: FilterPreset, intensity: Float = 1.0) {
        let image = engine.applyFilter(preset, intensity: intensity)
        displayImage(image)
        delegate?.imageEditorView(self, didUpdateImage: image)
    }

    /// Crop the image
    public func crop(to rect: CGRect) {
        do {
            let image = try engine.crop(to: rect)
            displayImage(image)
            delegate?.imageEditorView(self, didUpdateImage: image)
        } catch {
            delegate?.imageEditorView(self, didFailWithError: error)
        }
    }

    /// Rotate the image
    public func rotate(by angle: CGFloat) {
        let image = engine.rotate(by: angle)
        displayImage(image)
        delegate?.imageEditorView(self, didUpdateImage: image)
    }

    /// Flip horizontally
    public func flipHorizontal() {
        let image = engine.flipHorizontal()
        displayImage(image)
        delegate?.imageEditorView(self, didUpdateImage: image)
    }

    /// Flip vertically
    public func flipVertical() {
        let image = engine.flipVertical()
        displayImage(image)
        delegate?.imageEditorView(self, didUpdateImage: image)
    }

    /// Undo last operation
    public func undo() {
        if let image = engine.undo() {
            displayImage(image)
            delegate?.imageEditorView(self, didUpdateImage: image)
        }
    }

    /// Redo last operation
    public func redo() {
        if let image = engine.redo() {
            displayImage(image)
            delegate?.imageEditorView(self, didUpdateImage: image)
        }
    }

    /// Export current image
    public func exportImage(format: ExportFormat = .jpeg, quality: Float = 0.9) throws -> Data {
        return try engine.export(format: format, quality: quality)
    }

    /// Start drawing mode
    public func startDrawing() {
        drawingEnabled = true

        if activeDrawingLayer == nil {
            activeDrawingLayer = DrawingLayer(bounds: imageView.bounds)
            _ = engine.addLayer(name: "Drawing", image: UIImage())
        }
    }

    /// Stop drawing mode
    public func stopDrawing() {
        drawingEnabled = false
        currentDrawingPath = nil
    }

    // MARK: - Private Methods

    private func displayImage(_ image: UIImage) {
        imageView.image = image
        imageView.frame = CGRect(origin: .zero, size: image.size)
        scrollView.contentSize = image.size

        // Center image if smaller than scroll view
        centerImageView()
    }

    private func centerImageView() {
        let scrollViewSize = scrollView.bounds.size
        let imageViewSize = imageView.frame.size

        let horizontalInset = max(0, (scrollViewSize.width - imageViewSize.width) / 2)
        let verticalInset = max(0, (scrollViewSize.height - imageViewSize.height) / 2)

        scrollView.contentInset = UIEdgeInsets(
            top: verticalInset,
            left: horizontalInset,
            bottom: verticalInset,
            right: horizontalInset
        )
    }

    // MARK: - Gesture Handlers

    @objc private func handlePan(_ gesture: UIPanGestureRecognizer) {
        guard drawingEnabled else { return }

        let location = gesture.location(in: imageView)

        switch gesture.state {
        case .began:
            currentDrawingPath = DrawingPath(
                points: [location],
                color: drawingColor,
                width: drawingBrushSize,
                opacity: drawingOpacity,
                isEraser: isEraserMode
            )

        case .changed:
            currentDrawingPath?.points.append(location)

            // Update preview
            if let path = currentDrawingPath {
                activeDrawingLayer?.addPath(path)
            }

        case .ended, .cancelled:
            if let path = currentDrawingPath {
                activeDrawingLayer?.addPath(path)
                delegate?.imageEditorView(self, didFinishDrawing: path)
            }
            currentDrawingPath = nil

        default:
            break
        }
    }

    @objc private func handlePinch(_ gesture: UIPinchGestureRecognizer) {
        guard gesture.state == .changed else { return }
        scrollView.zoomScale *= gesture.scale
        gesture.scale = 1.0
    }

    @objc private func handleRotation(_ gesture: UIRotationGestureRecognizer) {
        guard gesture.state == .ended else { return }
        rotate(by: gesture.rotation)
        gesture.rotation = 0
    }
}

// MARK: - UIScrollViewDelegate

extension ImageEditorView: UIScrollViewDelegate {
    public func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        return imageView
    }

    public func scrollViewDidZoom(_ scrollView: UIScrollView) {
        centerImageView()
    }
}

// MARK: - Delegate Protocol

public protocol ImageEditorViewDelegate: AnyObject {
    func imageEditorView(_ view: ImageEditorView, didLoadImage image: UIImage)
    func imageEditorView(_ view: ImageEditorView, didUpdateImage image: UIImage)
    func imageEditorView(_ view: ImageEditorView, didFinishDrawing path: DrawingPath)
    func imageEditorView(_ view: ImageEditorView, didFailWithError error: Error)
}

// Make delegate methods optional
public extension ImageEditorViewDelegate {
    func imageEditorView(_ view: ImageEditorView, didLoadImage image: UIImage) {}
    func imageEditorView(_ view: ImageEditorView, didUpdateImage image: UIImage) {}
    func imageEditorView(_ view: ImageEditorView, didFinishDrawing path: DrawingPath) {}
    func imageEditorView(_ view: ImageEditorView, didFailWithError error: Error) {}
}
