/**
 * Drizzle Chat Session Repository Adapter
 *
 * Implements ChatSessionRepository interface using Drizzle ORM.
 */

import { eq, and, asc } from 'drizzle-orm';
import { nanoid } from 'nanoid';
import type { DrizzleDatabase } from '../../index.js';
import { chatSessions, chatMessages, type ChatSession, type ChatMessage } from '../../schema.js';
import type { ChatSessionRepository, CreateChatSessionData, CreateChatMessageData } from '../chat-session-repository.js';

export class DrizzleChatSessionRepository implements ChatSessionRepository {
  constructor(private db: DrizzleDatabase) {}

  async createSession(data: CreateChatSessionData): Promise<ChatSession> {
    const now = new Date();
    const id = nanoid();
    await this.db.insert(chatSessions).values({
      id,
      targetType: data.targetType,
      targetId: data.targetId,
      initiativeId: data.initiativeId,
      agentId: data.agentId ?? null,
      status: 'active',
      createdAt: now,
      updatedAt: now,
    });
    return this.findSessionById(id) as Promise<ChatSession>;
  }

  async findSessionById(id: string): Promise<ChatSession | null> {
    const rows = await this.db
      .select()
      .from(chatSessions)
      .where(eq(chatSessions.id, id))
      .limit(1);
    return rows[0] ?? null;
  }

  async findActiveSession(targetType: 'phase' | 'task', targetId: string): Promise<ChatSession | null> {
    const rows = await this.db
      .select()
      .from(chatSessions)
      .where(
        and(
          eq(chatSessions.targetType, targetType),
          eq(chatSessions.targetId, targetId),
          eq(chatSessions.status, 'active' as 'active' | 'closed'),
        ),
      )
      .limit(1);
    return rows[0] ?? null;
  }

  async findActiveSessionByAgentId(agentId: string): Promise<ChatSession | null> {
    const rows = await this.db
      .select()
      .from(chatSessions)
      .where(
        and(
          eq(chatSessions.agentId, agentId),
          eq(chatSessions.status, 'active' as 'active' | 'closed'),
        ),
      )
      .limit(1);
    return rows[0] ?? null;
  }

  async updateSession(id: string, data: { agentId?: string | null; status?: 'active' | 'closed' }): Promise<ChatSession> {
    const updates: Record<string, unknown> = { updatedAt: new Date() };
    if (data.agentId !== undefined) updates.agentId = data.agentId;
    if (data.status !== undefined) updates.status = data.status;
    await this.db
      .update(chatSessions)
      .set(updates)
      .where(eq(chatSessions.id, id));
    return this.findSessionById(id) as Promise<ChatSession>;
  }

  async createMessage(data: CreateChatMessageData): Promise<ChatMessage> {
    const id = nanoid();
    const now = new Date();
    await this.db.insert(chatMessages).values({
      id,
      chatSessionId: data.chatSessionId,
      role: data.role,
      content: data.content,
      changeSetId: data.changeSetId ?? null,
      createdAt: now,
    });
    const rows = await this.db
      .select()
      .from(chatMessages)
      .where(eq(chatMessages.id, id))
      .limit(1);
    return rows[0]!;
  }

  async findMessagesBySessionId(sessionId: string): Promise<ChatMessage[]> {
    return this.db
      .select()
      .from(chatMessages)
      .where(eq(chatMessages.chatSessionId, sessionId))
      .orderBy(asc(chatMessages.createdAt));
  }
}
