import fs from 'node:fs';
import { DatabaseSync } from 'node:sqlite';
import { CONFIG_DIR, QUEUE_DB_FILE } from '../config/paths';

export interface QueuedPrompt {
  promptId: string;
  sessionId: string;
  prompt: string;
  submittedAt: string;
  projectName: string;
  projectPathHash: string;
  projectDetectionSource: string;
  clientVersion: string;
}

export interface QueueRow {
  id: number;
  payload: QueuedPrompt;
  attempts: number;
  nextAttemptAt: number;
  status: 'pending' | 'failed';
}

let db: DatabaseSync | null = null;

function connection(): DatabaseSync {
  if (db) {
    return db;
  }

  fs.mkdirSync(CONFIG_DIR, { recursive: true });
  db = new DatabaseSync(QUEUE_DB_FILE);
  db.exec(`
    CREATE TABLE IF NOT EXISTS queue (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      payload TEXT NOT NULL,
      attempts INTEGER NOT NULL DEFAULT 0,
      next_attempt_at INTEGER NOT NULL DEFAULT 0,
      status TEXT NOT NULL DEFAULT 'pending',
      created_at INTEGER NOT NULL
    )
  `);

  return db;
}

export function enqueue(prompt: QueuedPrompt): void {
  connection()
    .prepare('INSERT INTO queue (payload, next_attempt_at, created_at) VALUES (?, ?, ?)')
    .run(JSON.stringify(prompt), 0, Date.now());
}

export function pendingCount(): number {
  const row = connection().prepare("SELECT COUNT(*) as c FROM queue WHERE status = 'pending'").get() as { c: number };

  return row.c;
}

export function dueRows(limit = 25): QueueRow[] {
  const rows = connection()
    .prepare("SELECT * FROM queue WHERE status = 'pending' AND next_attempt_at <= ? ORDER BY id ASC LIMIT ?")
    .all(Date.now(), limit) as Array<{ id: number; payload: string; attempts: number; next_attempt_at: number; status: string }>;

  return rows.map((row) => ({
    id: row.id,
    payload: JSON.parse(row.payload) as QueuedPrompt,
    attempts: row.attempts,
    nextAttemptAt: row.next_attempt_at,
    status: row.status as 'pending' | 'failed',
  }));
}

export function markDelivered(id: number): void {
  connection().prepare('DELETE FROM queue WHERE id = ?').run(id);
}

const MAX_BACKOFF_MS = 5 * 60 * 1000;

export function markRetry(id: number, attempts: number): void {
  const delay = Math.min(1000 * 2 ** attempts, MAX_BACKOFF_MS);
  connection()
    .prepare('UPDATE queue SET attempts = ?, next_attempt_at = ? WHERE id = ?')
    .run(attempts, Date.now() + delay, id);
}

export function markFailed(id: number): void {
  connection().prepare("UPDATE queue SET status = 'failed' WHERE id = ?").run(id);
}

export function close(): void {
  db?.close();
  db = null;
}
