import APIClient
import ComposableArchitecture
import Foundation

/// Wrapper to make OrpheusChatRepository usable as a TCA dependency
@DependencyClient
public struct OrpheusClient {
    public var messages: @Sendable () async -> AsyncStream<IdentifiedArrayOf<OrpheusMessage>> = { .never }
    public var startNewSession: @Sendable () async -> Void = {}
    public var sendMessage: @Sendable (String) async throws -> Void = { _ in }
    public var registerModelChange: @Sendable (String) async -> Void = { _ in }
    public var close: @Sendable () async -> Void = {}
}

extension OrpheusClient: DependencyKey {
    public static var liveValue: Self {
        @Dependency(\.continuousClock) var clock

        // Create handlers
        let messageContentHandler = MessageContentHandler()
        let messageErrorHandler = MessageErrorHandler()
        let partialJsonExtractor = PartialJsonExtractor()
        let messageFinishedHandler = MessageFinishedHandler()
        let messageToolCallHandler = MessageToolCallHandler(partialJsonExtractor: partialJsonExtractor)
        let toolCallContentHandler = ToolCallContentHandler()
        let toolCallFailureHandler = ToolCallFailureHandler()
        
        // ToolCallResultHandler no longer needs clipsService - clip fetching is handled in repository layer
        let toolCallResultHandler = ToolCallResultHandler()

        // Create projects repository for workspace registration
//        let projectsRepository = ProjectsRepository()
        
        // Create event processor
        let eventProcessor = OrpheusRealtimeEventProcessor(
            messageContentHandler: messageContentHandler,
            messageToolCallHandler: messageToolCallHandler,
            messageFinishedHandler: messageFinishedHandler,
            messageErrorHandler: messageErrorHandler,
            toolCallContentHandler: toolCallContentHandler,
            toolCallResultHandler: toolCallResultHandler,
            toolCallFailureHandler: toolCallFailureHandler
        )
        
        // Create session store
        let sessionStore = OrpheusSessionStore()

        // Create Orpheus service first (needed for Ably auth)
        let orpheusService = OrpheusService()
        
        // Create connection manager
        let connectionManager = OrpheusConnectionManager()
        
        // Create repository
        let repository = OrpheusChatRepository(
            orpheusService: orpheusService,
            sessionStore: sessionStore,
            connectionManager: connectionManager,
            realtimeEventProcessor: eventProcessor
        )
        
        return Self(
            messages: { return await repository.messages },
            startNewSession: { await repository.startNewSession() },
            sendMessage: { content in try await repository.sendMessage(content: content) },
            registerModelChange: { modelName in await repository.registerModelChange(modelName: modelName) },
            close: { await repository.close() }
        )
    }
    
    
    public static let testValue: Self = {
        return Self(
            messages: { .never },
            startNewSession: { },
            sendMessage: { _ in },
            registerModelChange: { _ in },
            close: { }
        )
    }()
}

extension OrpheusClient: TestDependencyKey {
    public static let previewValue: Self = Self(
        messages: { .never },
        startNewSession: { },
        sendMessage: { _ in },
        registerModelChange: { _ in },
        close: { }
    )
}

extension DependencyValues {
    public var orpheusClient: OrpheusClient {
        get { self[OrpheusClient.self] }
        set { self[OrpheusClient.self] = newValue }
    }
}
