import Database = require('better-sqlite3');
import { tryDecompressToString, hasZstdMagic } from './zstd_decode.js';

export interface MessageRow {
  localId: number;
  serverId: bigint | null;
  localType: number;
  realSenderId: bigint | null;
  createTime: number;
  content: string;
  tableName: string;
}

export class MessageRepo {
  private readonly db: Database.Database;
  constructor(private readonly dbPath: string) {
    this.db = new Database(dbPath, { readonly: true, fileMustExist: true });
  }

  listMsgTables(): string[] {
    const rows = this.db.prepare(
      "SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'Msg\\_%' ESCAPE '\\'"
    ).all() as { name: string }[];
    return rows.map(r => r.name);
  }

  maxCreateTime(tableName: string): number {
    const row = this.db.prepare(
      `SELECT IFNULL(MAX(create_time), 0) AS ts FROM "${tableName}"`
    ).get() as { ts: number };
    return row.ts;
  }

  async listSince(tableName: string, lastTs: number, limit = 500): Promise<MessageRow[]> {
    const rows = this.db.prepare(
      `SELECT local_id, server_id, local_type, real_sender_id, create_time, message_content
       FROM "${tableName}" WHERE create_time > @ts ORDER BY create_time ASC LIMIT ${limit}`
    ).all({ ts: lastTs }) as any[];
    const result: MessageRow[] = [];
    for (const r of rows) {
      const raw = r.message_content instanceof Buffer
        ? r.message_content
        : r.message_content != null
          ? Buffer.from(String(r.message_content), 'utf8')
          : Buffer.alloc(0);
      const content = hasZstdMagic(raw) ? await tryDecompressToString(raw) : raw.toString('utf8');
      result.push({
        localId: r.local_id,
        serverId: r.server_id != null ? BigInt(r.server_id) : null,
        localType: r.local_type,
        realSenderId: r.real_sender_id != null ? BigInt(r.real_sender_id) : null,
        createTime: r.create_time,
        content,
        tableName,
      });
    }
    return result;
  }

  close(): void { this.db.close(); }
}
