import { randomUUID } from "node:crypto";
import type { AppDatabase } from "../db/database.js";

export type ChatSessionRecord = {
  id: string;
  user_id: string;
  title: string | null;
  system_prompt: string | null;
  created_at: string;
  updated_at: string;
};

export type ChatMessageRecord = {
  id: string;
  session_id: string;
  user_id: string;
  role: "user" | "assistant" | "system" | "tool";
  content: string;
  metadata: string | null;
  created_at: string;
};

export function createSessionRepository(db: AppDatabase) {
  return {
    list(userId: string): ChatSessionRecord[] {
      return db
        .prepare("SELECT * FROM chat_sessions WHERE user_id = ? ORDER BY updated_at DESC")
        .all(userId) as ChatSessionRecord[];
    },

    create(userId: string, title: string | null): ChatSessionRecord {
      const now = new Date().toISOString();
      const session: ChatSessionRecord = {
        id: randomUUID(),
        user_id: userId,
        title,
        system_prompt: null,
        created_at: now,
        updated_at: now,
      };

      db.prepare(
        "INSERT INTO chat_sessions (id, user_id, title, created_at, updated_at) VALUES (?, ?, ?, ?, ?)",
      ).run(session.id, session.user_id, session.title, session.created_at, session.updated_at);

      return session;
    },

    get(userId: string, sessionId: string): ChatSessionRecord | null {
      return (
        (db.prepare("SELECT * FROM chat_sessions WHERE id = ? AND user_id = ?").get(sessionId, userId) as
          | ChatSessionRecord
          | undefined) ?? null
      );
    },

    delete(userId: string, sessionId: string): boolean {
      const result = db.prepare("DELETE FROM chat_sessions WHERE id = ? AND user_id = ?").run(sessionId, userId);
      return result.changes > 0;
    },

    deleteAllForUser(userId: string): number {
      const result = db
        .prepare("DELETE FROM chat_sessions WHERE user_id = ?")
        .run(userId);
      return Number(result.changes ?? 0);
    },

    touch(userId: string, sessionId: string): void {
      db.prepare("UPDATE chat_sessions SET updated_at = ? WHERE id = ? AND user_id = ?").run(
        new Date().toISOString(),
        sessionId,
        userId,
      );
    },

    updateTitle(userId: string, sessionId: string, title: string): void {
      db.prepare("UPDATE chat_sessions SET title = ?, updated_at = ? WHERE id = ? AND user_id = ?").run(
        title,
        new Date().toISOString(),
        sessionId,
        userId,
      );
    },

    updateSystemPrompt(userId: string, sessionId: string, prompt: string | null): boolean {
      const normalized = prompt && prompt.trim().length > 0 ? prompt.trim() : null;
      const result = db
        .prepare(
          "UPDATE chat_sessions SET system_prompt = ?, updated_at = ? WHERE id = ? AND user_id = ?",
        )
        .run(normalized, new Date().toISOString(), sessionId, userId);
      return result.changes > 0;
    },
  };
}

export function createMessageRepository(db: AppDatabase) {
  return {
    listForSession(userId: string, sessionId: string): ChatMessageRecord[] {
      return db
        .prepare("SELECT * FROM chat_messages WHERE session_id = ? AND user_id = ? ORDER BY created_at ASC")
        .all(sessionId, userId) as ChatMessageRecord[];
    },

    create(input: {
      sessionId: string;
      userId: string;
      role: ChatMessageRecord["role"];
      content: string;
      metadata?: unknown;
    }): ChatMessageRecord {
      const message: ChatMessageRecord = {
        id: randomUUID(),
        session_id: input.sessionId,
        user_id: input.userId,
        role: input.role,
        content: input.content,
        metadata: input.metadata ? JSON.stringify(input.metadata) : null,
        created_at: new Date().toISOString(),
      };

      db.prepare(
        `INSERT INTO chat_messages
          (id, session_id, user_id, role, content, metadata, created_at)
          VALUES (?, ?, ?, ?, ?, ?, ?)`,
      ).run(
        message.id,
        message.session_id,
        message.user_id,
        message.role,
        message.content,
        message.metadata,
        message.created_at,
      );

      return message;
    },
  };
}
