import ExpoModulesCore
import UIKit
import CoreImage

public class ImageEditorModule: Module {
    private var editorEngine: ImageEditorEngine?

    public func definition() -> ModuleDefinition {
        Name("ImageEditor")

        // MARK: - Events

        Events("onImageLoaded", "onImageUpdated", "onExportProgress", "onError")

        // MARK: - Functions

        // Load image from path
        AsyncFunction("loadImage") { (path: String, promise: Promise) in
            DispatchQueue.global(qos: .userInitiated).async {
                do {
                    if self.editorEngine == nil {
                        self.editorEngine = ImageEditorEngine()
                    }

                    let image = try self.editorEngine!.loadImage(from: path)

                    DispatchQueue.main.async {
                        self.sendEvent("onImageLoaded", [
                            "width": image.size.width,
                            "height": image.size.height
                        ])
                        promise.resolve([
                            "success": true,
                            "width": image.size.width,
                            "height": image.size.height
                        ])
                    }
                } catch {
                    DispatchQueue.main.async {
                        self.sendEvent("onError", ["error": error.localizedDescription])
                        promise.reject("LOAD_ERROR", error.localizedDescription)
                    }
                }
            }
        }

        // Apply adjustments
        AsyncFunction("applyAdjustments") { (params: [String: Float], promise: Promise) in
            guard let engine = self.editorEngine else {
                promise.reject("NO_ENGINE", "Editor engine not initialized")
                return
            }

            DispatchQueue.global(qos: .userInitiated).async {
                var adjustments = ImageAdjustments()
                adjustments.brightness = params["brightness"] ?? 0.0
                adjustments.contrast = params["contrast"] ?? 1.0
                adjustments.saturation = params["saturation"] ?? 1.0
                adjustments.exposure = params["exposure"] ?? 0.0
                adjustments.highlights = params["highlights"] ?? 1.0
                adjustments.shadows = params["shadows"] ?? 0.0
                adjustments.temperature = params["temperature"] ?? 0.0
                adjustments.tint = params["tint"] ?? 0.0
                adjustments.sharpness = params["sharpness"] ?? 0.0
                adjustments.noiseReduction = params["noiseReduction"] ?? 0.0
                adjustments.vignette = params["vignette"] ?? 0.0

                let image = engine.applyAdjustments(adjustments)

                DispatchQueue.main.async {
                    self.sendEvent("onImageUpdated", [:])
                    promise.resolve(["success": true])
                }
            }
        }

        // Apply filter
        AsyncFunction("applyFilter") { (filterType: String, intensity: Float, promise: Promise) in
            guard let engine = self.editorEngine else {
                promise.reject("NO_ENGINE", "Editor engine not initialized")
                return
            }

            guard let preset = FilterPreset(rawValue: filterType) else {
                promise.reject("INVALID_FILTER", "Invalid filter type: \(filterType)")
                return
            }

            DispatchQueue.global(qos: .userInitiated).async {
                let image = engine.applyFilter(preset, intensity: intensity)

                DispatchQueue.main.async {
                    self.sendEvent("onImageUpdated", [:])
                    promise.resolve(["success": true])
                }
            }
        }

        // Crop image
        AsyncFunction("crop") { (x: Double, y: Double, width: Double, height: Double, promise: Promise) in
            guard let engine = self.editorEngine else {
                promise.reject("NO_ENGINE", "Editor engine not initialized")
                return
            }

            DispatchQueue.global(qos: .userInitiated).async {
                do {
                    let rect = CGRect(x: x, y: y, width: width, height: height)
                    let image = try engine.crop(to: rect)

                    DispatchQueue.main.async {
                        self.sendEvent("onImageUpdated", [:])
                        promise.resolve([
                            "success": true,
                            "width": image.size.width,
                            "height": image.size.height
                        ])
                    }
                } catch {
                    DispatchQueue.main.async {
                        promise.reject("CROP_ERROR", error.localizedDescription)
                    }
                }
            }
        }

        // Rotate image
        AsyncFunction("rotate") { (angle: Double, promise: Promise) in
            guard let engine = self.editorEngine else {
                promise.reject("NO_ENGINE", "Editor engine not initialized")
                return
            }

            DispatchQueue.global(qos: .userInitiated).async {
                let image = engine.rotate(by: CGFloat(angle))

                DispatchQueue.main.async {
                    self.sendEvent("onImageUpdated", [:])
                    promise.resolve(["success": true])
                }
            }
        }

        // Flip horizontal
        AsyncFunction("flipHorizontal") { (promise: Promise) in
            guard let engine = self.editorEngine else {
                promise.reject("NO_ENGINE", "Editor engine not initialized")
                return
            }

            DispatchQueue.global(qos: .userInitiated).async {
                let image = engine.flipHorizontal()

                DispatchQueue.main.async {
                    self.sendEvent("onImageUpdated", [:])
                    promise.resolve(["success": true])
                }
            }
        }

        // Flip vertical
        AsyncFunction("flipVertical") { (promise: Promise) in
            guard let engine = self.editorEngine else {
                promise.reject("NO_ENGINE", "Editor engine not initialized")
                return
            }

            DispatchQueue.global(qos: .userInitiated).async {
                let image = engine.flipVertical()

                DispatchQueue.main.async {
                    self.sendEvent("onImageUpdated", [:])
                    promise.resolve(["success": true])
                }
            }
        }

        // Resize image
        AsyncFunction("resize") { (width: Double, height: Double, promise: Promise) in
            guard let engine = self.editorEngine else {
                promise.reject("NO_ENGINE", "Editor engine not initialized")
                return
            }

            DispatchQueue.global(qos: .userInitiated).async {
                let size = CGSize(width: width, height: height)
                let image = engine.resize(to: size)

                DispatchQueue.main.async {
                    self.sendEvent("onImageUpdated", [:])
                    promise.resolve(["success": true])
                }
            }
        }

        // Undo
        Function("undo") { () -> Bool in
            guard let engine = self.editorEngine else { return false }
            if let _ = engine.undo() {
                self.sendEvent("onImageUpdated", [:])
                return true
            }
            return false
        }

        // Redo
        Function("redo") { () -> Bool in
            guard let engine = self.editorEngine else { return false }
            if let _ = engine.redo() {
                self.sendEvent("onImageUpdated", [:])
                return true
            }
            return false
        }

        // Can undo
        Function("canUndo") { () -> Bool in
            guard let engine = self.editorEngine else { return false }
            return engine.historyManager.canUndo
        }

        // Can redo
        Function("canRedo") { () -> Bool in
            guard let engine = self.editorEngine else { return false }
            return engine.historyManager.canRedo
        }

        // Export image
        AsyncFunction("export") { (options: [String: Any], promise: Promise) in
            guard let engine = self.editorEngine else {
                promise.reject("NO_ENGINE", "Editor engine not initialized")
                return
            }

            DispatchQueue.global(qos: .userInitiated).async {
                do {
                    let formatString = options["format"] as? String ?? "jpeg"
                    let quality = options["quality"] as? Float ?? 0.9
                    let maxDimension = options["maxDimension"] as? Int

                    let format: ExportFormat
                    switch formatString.lowercased() {
                    case "png":
                        format = .png
                    case "heic":
                        format = .heic
                    default:
                        format = .jpeg
                    }

                    // Create export options
                    var exportOptions = ImageEditorEngine.ExportOptions(format: format, quality: quality, maxDimension: maxDimension)

                    // Add progress callback
                    exportOptions.progressCallback = { progress in
                        DispatchQueue.main.async {
                            self.sendEvent("onExportProgress", ["progress": progress])
                        }
                    }

                    let data = try engine.export(options: exportOptions)

                    // Save to temporary file
                    let tempDir = FileManager.default.temporaryDirectory
                    let filename = "exported_\(UUID().uuidString).\(formatString)"
                    let fileURL = tempDir.appendingPathComponent(filename)

                    try data.write(to: fileURL)

                    DispatchQueue.main.async {
                        promise.resolve([
                            "success": true,
                            "uri": fileURL.absoluteString,
                            "size": data.count
                        ])
                    }
                } catch {
                    DispatchQueue.main.async {
                        self.sendEvent("onError", ["error": error.localizedDescription])
                        promise.reject("EXPORT_ERROR", error.localizedDescription)
                    }
                }
            }
        }

        // Get available filters
        Function("getAvailableFilters") { () -> [String] in
            return FilterPreset.allCases.map { $0.rawValue }
        }

        // MARK: - LUT Functions

        // Load LUT from file
        AsyncFunction("loadLUT") { (name: String, filePath: String, promise: Promise) in
            guard let engine = self.editorEngine else {
                promise.reject("NO_ENGINE", "Editor engine not initialized")
                return
            }

            DispatchQueue.global(qos: .userInitiated).async {
                do {
                    let fileURL = URL(fileURLWithPath: filePath)
                    try engine.filterPipeline.loadLUT(name: name, fileURL: fileURL)

                    DispatchQueue.main.async {
                        promise.resolve([
                            "success": true,
                            "name": name
                        ])
                    }
                } catch let error as LUTParserError {
                    DispatchQueue.main.async {
                        self.sendEvent("onError", ["error": "LUT Parse Error: \(error.localizedDescription)"])
                        promise.reject("LUT_PARSE_ERROR", error.localizedDescription)
                    }
                } catch let error as LUTFilterError {
                    DispatchQueue.main.async {
                        self.sendEvent("onError", ["error": "LUT Filter Error: \(error.localizedDescription)"])
                        promise.reject("LUT_FILTER_ERROR", error.localizedDescription)
                    }
                } catch {
                    DispatchQueue.main.async {
                        self.sendEvent("onError", ["error": error.localizedDescription])
                        promise.reject("LUT_ERROR", error.localizedDescription)
                    }
                }
            }
        }

        // Apply LUT to current image
        AsyncFunction("applyLUT") { (name: String, intensity: Float, promise: Promise) in
            guard let engine = self.editorEngine else {
                promise.reject("NO_ENGINE", "Editor engine not initialized")
                return
            }

            guard engine.sourceImage != nil else {
                promise.reject("NO_IMAGE", "No image loaded")
                return
            }

            DispatchQueue.global(qos: .userInitiated).async {
                do {
                    let clampedIntensity = max(0.0, min(1.0, intensity))
                guard let baseLayer = engine.layerManager.layers.first,
                      let ciImage = baseLayer.image else {
                    throw ImageEditorError.imageLoadFailed
                }

                let filteredImage = try engine.filterPipeline.applyLUT(
                    named: name,
                    to: ciImage,
                    intensity: clampedIntensity
                )

                // Update layer with filtered CIImage
                baseLayer.image = filteredImage
                    engine.historyManager.saveState(engine.createEditorState())

                    DispatchQueue.main.async {
                        self.sendEvent("onImageUpdated", [
                            "operation": "applyLUT",
                            "lutName": name,
                            "intensity": clampedIntensity
                        ])
                        promise.resolve([
                            "success": true,
                            "intensity": clampedIntensity
                        ])
                    }
                } catch let error as LUTFilterError {
                    DispatchQueue.main.async {
                        self.sendEvent("onError", ["error": "LUT Filter Error: \(error.localizedDescription)"])
                        promise.reject("LUT_FILTER_ERROR", error.localizedDescription)
                    }
                } catch {
                    DispatchQueue.main.async {
                        self.sendEvent("onError", ["error": error.localizedDescription])
                        promise.reject("LUT_ERROR", error.localizedDescription)
                    }
                }
            }
        }

        // Clear LUT cache
        Function("clearLUTCache") { () in
            self.editorEngine?.filterPipeline.clearLUTCache()
        }

        // Reset editor
        Function("reset") { () in
            self.editorEngine = nil
        }
    }
}
