import ComposableArchitecture
import Foundation

/// Strategy protocol for handling Orpheus real-time events.
///
/// Each handler is responsible for processing a specific event type and returning
/// the appropriate result (message updates, no op, or side effects).
public protocol OrpheusEventHandler {
    func handle(
        event: OrpheusRealtimeEvent,
        session: OrpheusSession
    ) -> EventHandlerResult
}

/// Result of processing an event handler.
///
/// - messagesUpdated: The handler updated the message list
/// - updateMessage: Update a specific message with a transform and optional clip IDs to fetch
/// - noOp: Event handled but no processing needed (e.g., connection events, logging-only, no changes)
public enum EventHandlerResult: Equatable {
    case messagesUpdated(IdentifiedArrayOf<OrpheusMessage>)
    case updateMessage(messageId: String, transform: (OrpheusMessage) -> OrpheusMessage, clipIdsToFetch: [String]? = nil)
    case noOp
    
    // MARK: - Equatable
    
    public static func == (lhs: EventHandlerResult, rhs: EventHandlerResult) -> Bool {
        switch (lhs, rhs) {
        case (.noOp, .noOp):
            return true
        case (.messagesUpdated(let lhsMessages), .messagesUpdated(let rhsMessages)):
            return lhsMessages == rhsMessages
        case (.updateMessage(let lhsId, _, let lhsClipIds), .updateMessage(let rhsId, _, let rhsClipIds)):
            // Note: We can't compare transform closures, so we compare messageId and clipIds
            return lhsId == rhsId && lhsClipIds == rhsClipIds
        default:
            return false
        }
    }
}

/// Represents a side effect that needs to be executed asynchronously
public struct SideEffect {
    public let execute: ([OrpheusMessage]) async -> SideEffectResult
    
    public init(execute: @escaping ([OrpheusMessage]) async -> SideEffectResult) {
        self.execute = execute
    }
}

/// Result of executing a side effect.
///
/// Side effects are async operations (like API calls) that may produce additional message updates.
public enum SideEffectResult: Equatable {
    case messagesUpdated([OrpheusMessage])
    case noOp
    
    // MARK: - Equatable
    
    public static func == (lhs: SideEffectResult, rhs: SideEffectResult) -> Bool {
        switch (lhs, rhs) {
        case (.messagesUpdated(let lhsMessages), .messagesUpdated(let rhsMessages)):
            return lhsMessages == rhsMessages
        case (.noOp, .noOp):
            return true
        default:
            return false
        }
    }
}

