import Foundation
import React

@objc(PixelData)
class PixelData: NSObject {
    
    // MARK: - Module Setup
    
    @objc
    static func requiresMainQueueSetup() -> Bool {
        return false
    }
    
    @objc
    static func moduleName() -> String {
        return "PixelData"
    }
    
    // MARK: - getPixelData
    
    @objc
    func getPixelData(
        _ options: NSDictionary,
        resolver resolve: @escaping RCTPromiseResolveBlock,
        rejecter reject: @escaping RCTPromiseRejectBlock
    ) {
        Task {
            do {
                guard let optionsDict = options as? [String: Any] else {
                    throw PixelDataError.invalidSource("Invalid options format")
                }
                
                let parsedOptions = try GetPixelDataOptions(from: optionsDict)
                let image = try await ImageLoader.loadImage(from: parsedOptions.source)
                let result = try PixelProcessor.process(image: image, options: parsedOptions)
                
                resolve(result.toDictionary())
            } catch let error as PixelDataError {
                reject(error.code, error.message, nil)
            } catch {
                reject("UNKNOWN", error.localizedDescription, nil)
            }
        }
    }
    
    // MARK: - batchGetPixelData
    
    @objc
    func batchGetPixelData(
        _ optionsArray: NSArray,
        batchOptions: NSDictionary,
        resolver resolve: @escaping RCTPromiseResolveBlock,
        rejecter reject: @escaping RCTPromiseRejectBlock
    ) {
        Task {
            let startTime = CFAbsoluteTimeGetCurrent()
            
            guard let optionsList = optionsArray as? [[String: Any]] else {
                reject("INVALID_SOURCE", "Invalid options array format", nil)
                return
            }
            
            // Parse batch options
            let concurrency = (batchOptions["concurrency"] as? Int) ?? 4
            
            // Process images with concurrency limit
            var results: [[String: Any]] = Array(repeating: [:], count: optionsList.count)
            
            await withTaskGroup(of: (Int, [String: Any]).self) { group in
                var activeCount = 0
                var index = 0
                
                for (idx, optionsDict) in optionsList.enumerated() {
                    // Wait if we've reached concurrency limit
                    while activeCount >= concurrency {
                        if let completed = await group.next() {
                            results[completed.0] = completed.1
                            activeCount -= 1
                        }
                    }
                    
                    let currentIndex = idx
                    activeCount += 1
                    
                    group.addTask {
                        do {
                            let parsedOptions = try GetPixelDataOptions(from: optionsDict)
                            let image = try await ImageLoader.loadImage(from: parsedOptions.source)
                            let result = try PixelProcessor.process(image: image, options: parsedOptions)
                            return (currentIndex, result.toDictionary())
                        } catch let error as PixelDataError {
                            return (currentIndex, [
                                "error": true,
                                "message": error.message,
                                "code": error.code,
                                "index": currentIndex
                            ])
                        } catch {
                            return (currentIndex, [
                                "error": true,
                                "message": error.localizedDescription,
                                "code": "UNKNOWN",
                                "index": currentIndex
                            ])
                        }
                    }
                }
                
                // Collect remaining results
                for await completed in group {
                    results[completed.0] = completed.1
                }
            }
            
            let endTime = CFAbsoluteTimeGetCurrent()
            let totalTimeMs = (endTime - startTime) * 1000
            
            resolve([
                "results": results,
                "totalTimeMs": totalTimeMs
            ])
        }
    }
}
