import ComposableArchitecture
import Foundation

/// Store for managing Orpheus session state.
///
/// This is a simple state store that holds the current session and can reduce events
/// to update the session state. Messages are stored directly in the session.
public actor OrpheusSessionStore {
    @Dependency(\.date) private var date
    private let _sessionFlow = AsyncCurrentValueSubject<OrpheusSession?>(initialValue: nil)
    
    /// Current session flow. Emits the current session, or nil if no session exists.
    public var sessionFlow: AsyncCurrentValueSubject<OrpheusSession?> {
        _sessionFlow
    }
    
    /// Starts a new session, clearing any existing session.
    public func startNewSession() -> OrpheusSession {
        let session = OrpheusSession(
            id: UUID().uuidString,
            createdAt: date.now.timeIntervalSince1970,
            workspaceId: nil,
            messages: []
        )
        _sessionFlow.value = session
        return session
    }
    
    /// Reduces an event to update the session state.
    /// Note: This method is kept for backward compatibility but direct methods are preferred.
    public func reduce(_ event: OrpheusSessionEvent) {
        guard let currentSession = _sessionFlow.value else {
            print("⚠️ Event \(event) dispatched before session initialization")
            return
        }
        
        let updatedSession: OrpheusSession
        
        switch event {
        case .messageAdded(let message):
            updatedSession = currentSession.addMessage(message)
            
        case .messageUpdated(let messageId, let updatedMessage, _):
            // For reduce(), we just update the message directly
            // clipIdsToFetch is handled in the repository layer
            if let updated = currentSession.updateMessage(messageId: messageId, transform: { _ in updatedMessage }) {
                updatedSession = updated
            } else {
                print("⚠️ Message not found for update: \(messageId)")
                return
            }
            
        case .messagesReplaced(let newMessages):
            updatedSession = currentSession.copy(messages: newMessages)
            
        case .workspaceUpdated(let workspaceId):
            print("📡 Updated session workspace: \(workspaceId)")
            updatedSession = currentSession.copy(workspaceId: workspaceId)
            
        case .noOp:
            // No operation needed - event handled but no state change
            return
        }
        
        _sessionFlow.value = updatedSession
    }
    
    /// Adds a message to the current session.
    public func addMessage(_ message: OrpheusMessage) {
        guard let currentSession = _sessionFlow.value else {
            print("⚠️ AddMessage called before session initialization")
            return
        }
        print("📡 Adding message: \(message.id)")
        _sessionFlow.value = currentSession.addMessage(message)
    }
    
    /// Updates a message via a transform function.
    public func updateMessage(
        messageId: String,
        transform: @escaping (OrpheusMessage) -> OrpheusMessage
    ) {
        guard let currentSession = _sessionFlow.value else {
            print("⚠️ UpdateMessage called before session initialization")
            return
        }
        print("📡 Updating message: \(messageId)")
        if let updated = currentSession.updateMessage(messageId: messageId, transform: transform) {
            _sessionFlow.value = updated
        } else {
            print("⚠️ Message not found for update: \(messageId)")
        }
    }
    
    /// Updates the workspace ID for the session.
    public func updateWorkspace(_ workspaceId: String) {
        guard let currentSession = _sessionFlow.value else {
            print("⚠️ UpdateWorkspace called before session initialization")
            return
        }
        print("📡 Updated session workspace: \(workspaceId)")
        _sessionFlow.value = currentSession.copy(workspaceId: workspaceId)
    }
}

