import ComposableArchitecture
import Foundation

/// Represents a message in an Orpheus chat session
public struct OrpheusMessage: Equatable, Identifiable {
    public let id: String // messageId
    public let role: MessageRole
    public let content: String
    public let timestamp: TimeInterval // Duration in seconds
    public let contentType: MessageContentType
    public let accumulatingToolCall: ToolCall?
    public let generatedClips: [String] // clip IDs, simplified from LocalClipData
    public let isStreaming: Bool
    
    public init(
        id: String,
        role: MessageRole,
        content: String,
        timestamp: TimeInterval,
        contentType: MessageContentType = .chat,
        accumulatingToolCall: ToolCall? = nil,
        generatedClips: [String] = [],
        isStreaming: Bool = true
    ) {
        self.id = id
        self.role = role
        self.content = content
        self.timestamp = timestamp
        self.contentType = contentType
        self.accumulatingToolCall = accumulatingToolCall
        self.generatedClips = generatedClips
        self.isStreaming = isStreaming
    }
    
    /// Creates a copy with updated fields
    public func copy(
        content: String? = nil,
        contentType: MessageContentType? = nil,
        accumulatingToolCall: ToolCall?? = nil,
        generatedClips: [String]? = nil,
        isStreaming: Bool? = nil
    ) -> OrpheusMessage {
        OrpheusMessage(
            id: id,
            role: role,
            content: content ?? self.content,
            timestamp: timestamp,
            contentType: contentType ?? self.contentType,
            accumulatingToolCall: accumulatingToolCall ?? self.accumulatingToolCall,
            generatedClips: generatedClips ?? self.generatedClips,
            isStreaming: isStreaming ?? self.isStreaming
        )
    }
}

/// Represents an Orpheus chat session
public struct OrpheusSession: Equatable, Identifiable {
    public let id: String // sessionId
    public let createdAt: TimeInterval
    public var workspaceId: String? // Optional workspace ID
    public var messages: IdentifiedArrayOf<OrpheusMessage> // Messages are stored in the session

    public init(
        id: String,
        createdAt: TimeInterval,
        workspaceId: String? = nil,
        messages: IdentifiedArrayOf<OrpheusMessage> = []
    ) {
        self.id = id
        self.createdAt = createdAt
        self.workspaceId = workspaceId
        self.messages = messages
    }
    
    /// Creates a copy with updated fields
    public func copy(
        workspaceId: String?? = nil,
        messages: IdentifiedArrayOf<OrpheusMessage>? = nil
    ) -> OrpheusSession {
        OrpheusSession(
            id: id,
            createdAt: createdAt,
            workspaceId: workspaceId ?? self.workspaceId,
            messages: messages ?? self.messages
        )
    }
    
    /// Adds a message to the session
    public func addMessage(_ message: OrpheusMessage) -> OrpheusSession {
        var updatedMessages = messages
        updatedMessages.append(message)
        return copy(messages: updatedMessages)
    }
    
    /// Updates a message via a transform function
    public func updateMessage(
        messageId: String,
        transform: (OrpheusMessage) -> OrpheusMessage
    ) -> OrpheusSession? {
        guard let messageIndex = messages.index(id: messageId) else {
            return nil
        }
        var updatedMessages = messages
        updatedMessages[messageIndex] = transform(updatedMessages[messageIndex])
        return copy(messages: updatedMessages)
    }
}

/// Role of a message in the chat
public enum MessageRole: Equatable {
    case user
    case assistant
}

/// Content type of a message
public enum MessageContentType: Equatable {
    case chat
    case toolCallContent
}

/// Represents a tool call in progress
public struct ToolCall: Equatable {
    public let id: String?
    public let functionCall: FunctionCall
    
    public init(id: String?, functionCall: FunctionCall) {
        self.id = id
        self.functionCall = functionCall
    }
}

/// Represents a function call within a tool call
public struct FunctionCall: Equatable {
    public let name: String?
    public let arguments: String?
    
    public init(name: String?, arguments: String?) {
        self.name = name
        self.arguments = arguments
    }
}

