import Foundation
import React

// MARK: - BrickError Protocol

/// Error protocol for Brick modules.
/// Conforming to this protocol propagates all error properties to JavaScript.
public protocol BrickError: Error {
    /// Error message (accessed as error.message in JS)
    var message: String { get }

    /// Error code (accessed as error.code in JS, optional)
    var code: String? { get }

    /// Additional properties (accessed as error.userInfo.xxx in JS)
    var userInfo: [String: Any]? { get }

    /// Convert to NSError (for React Native reject)
    func asNSError() -> NSError
}

public extension BrickError {
    /// Default code implementation
    var code: String? { nil }

    /// Default userInfo implementation
    var userInfo: [String: Any]? { nil }

    /// Default NSError conversion implementation
    func asNSError() -> NSError {
        var info: [String: Any] = userInfo ?? [:]
        info["code"] = code ?? "EXECUTION_ERROR"
        info["message"] = message
        info[NSLocalizedDescriptionKey] = message
        return NSError(domain: "BrickModule", code: 0, userInfo: info)
    }

    /// Error code to use when calling reject
    var rejectCode: String {
        code ?? "EXECUTION_ERROR"
    }
}

// MARK: - BrickModuleBase

/**
 * Base class for all Brick modules
 * Provides common functionality including event emission
 */
open class BrickModuleBase: NSObject {
    /// The name of the module (required for registration)
    public let moduleName: String
    
    /// The registry that manages this module (assigned during registration)
    public weak var registry: BrickModuleRegistry?
    
    public weak var bridgeProxy: RCTBridgeProxy?
    
    /// Initialize with module name
    public init(moduleName: String) {
        self.moduleName = moduleName
        super.init()
    }
    
    // Emit via Registry event map (ObjC++ injects typed handlers per event)
    public func emit(_ eventName: String, payload: [String: Any]) {
        guard let registry = registry else {
            print("⚠️ BrickModuleBase: registry not attached; cannot emit \(moduleName).\(eventName)")
            return
        }
        registry.emitEvent(module: moduleName, event: eventName, payload: payload)
    }
}

// MARK: - BrickModuleError

/**
 * Error types for Brick modules
 */
public enum BrickModuleError: BrickError {
    case typeMismatch(String)
    case executionError(String)
    case invalidDefinition(String)
    case methodNotFound(String)
    case moduleNotFound(String)

    public var code: String? {
        switch self {
        case .typeMismatch: return "TYPE_ERROR"
        case .executionError: return "EXECUTION_ERROR"
        case .invalidDefinition: return "DEFINITION_ERROR"
        case .methodNotFound: return "METHOD_NOT_FOUND"
        case .moduleNotFound: return "MODULE_NOT_FOUND"
        }
    }

    public var message: String {
        switch self {
        case .typeMismatch(let msg): return "Type mismatch: \(msg)"
        case .executionError(let msg): return "Execution error: \(msg)"
        case .invalidDefinition(let msg): return "Invalid definition: \(msg)"
        case .methodNotFound(let msg): return "Method not found: \(msg)"
        case .moduleNotFound(let msg): return "Module not found: \(msg)"
        }
    }
}


public protocol BrickModuleAddableViewControllerType: UIViewController {
    func addBrickModule(_ module: BrickModuleBase)
}


  
