/**
 * Memory Service
 *
 * DynamoDB-based service for storing and retrieving conversation session history.
 * Uses AWS SDK v3 with the DynamoDB Document Client for simplified operations.
 *
 * DynamoDB Schema:
 * - sessionId (String, PK): Unique session identifier
 * - messages (List): Array of ConversationMessage objects
 * - createdAt (String): ISO timestamp of session creation
 * - updatedAt (String): ISO timestamp of last update
 * - ttl (Number): Optional TTL for automatic expiration
 */

import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import {
    DynamoDBDocumentClient,
    GetCommand,
    UpdateCommand,
} from '@aws-sdk/lib-dynamodb';
import type { ConversationMessage, ConversationTurn } from '../types/chat.types';

export class MemoryService {
    private docClient: DynamoDBDocumentClient;
    private tableName: string;

    constructor() {
        const client = new DynamoDBClient({});
        this.docClient = DynamoDBDocumentClient.from(client, {
            marshallOptions: {
                removeUndefinedValues: true,
            },
        });
        this.tableName = process.env.MEMORY_TABLE_NAME || 'ai-chat-sessions';
    }

    /**
     * Retrieves conversation history for a given session.
     *
     * @param sessionId - Unique identifier for the session
     * @returns Array of conversation messages, or empty array if session doesn't exist
     */
    async get(sessionId: string): Promise<ConversationMessage[]> {
        const command = new GetCommand({
            TableName: this.tableName,
            Key: { sessionId },
            ProjectionExpression: 'messages',
        });

        const response = await this.docClient.send(command);

        if (!response.Item || !response.Item.messages) {
            return [];
        }

        return response.Item.messages as ConversationMessage[];
    }

    /**
     * Appends a conversation turn (user message + assistant response) to session history.
     * Creates the session if it doesn't exist.
     *
     * @param sessionId - Unique identifier for the session
     * @param turn - The conversation turn containing user message and assistant response
     */
    async append(sessionId: string, turn: ConversationTurn): Promise<void> {
        const timestamp = new Date().toISOString();

        const userMessage: ConversationMessage = {
            role: 'user',
            content: turn.user,
            timestamp,
        };

        const assistantMessage: ConversationMessage = {
            role: 'assistant',
            content: turn.assistant,
            timestamp,
        };

        const command = new UpdateCommand({
            TableName: this.tableName,
            Key: { sessionId },
            UpdateExpression: `
                SET messages = list_append(if_not_exists(messages, :empty), :newMessages),
                    updatedAt = :updatedAt,
                    createdAt = if_not_exists(createdAt, :createdAt)
            `,
            ExpressionAttributeValues: {
                ':empty': [],
                ':newMessages': [userMessage, assistantMessage],
                ':updatedAt': timestamp,
                ':createdAt': timestamp,
            },
        });

        await this.docClient.send(command);
    }
}
