const Database = require('better-sqlite3');
const path = require('path');
const log = require('./logger');

const DB_PATH = path.join('/mnt/webdata/storage', 'jobs.db');
const db = new Database(DB_PATH);

// WAL mode for better concurrency
db.pragma('journal_mode = WAL');
db.pragma('busy_timeout = 5000');

// Create jobs table
db.exec(`
  CREATE TABLE IF NOT EXISTS jobs (
    id TEXT PRIMARY KEY,
    type TEXT NOT NULL,
    status TEXT NOT NULL DEFAULT 'pending',
    payload TEXT NOT NULL DEFAULT '{}',
    result TEXT,
    progress INTEGER DEFAULT 0,
    error TEXT,
    created_at INTEGER NOT NULL,
    updated_at INTEGER NOT NULL,
    started_at INTEGER,
    finished_at INTEGER,
    user_id TEXT
  )
`);

db.exec(`CREATE INDEX IF NOT EXISTS idx_jobs_status ON jobs(status)`);
db.exec(`CREATE INDEX IF NOT EXISTS idx_jobs_type ON jobs(type)`);

// Migrate pre-existing DBs: add user_id column if missing.
try { db.exec(`ALTER TABLE jobs ADD COLUMN user_id TEXT`); } catch {}
// Reap jobs stuck in 'processing' after a crash/restart (never reaped by cleanup otherwise).
try {
  const t = Date.now();
  db.prepare(`UPDATE jobs SET status = 'error', error = 'Прервано перезапуском сервиса', finished_at = ?, updated_at = ? WHERE status = 'processing'`).run(t, t);
} catch {}

// Prepared statements
const stmts = {
  insert: db.prepare(`INSERT INTO jobs (id, type, status, payload, progress, created_at, updated_at, user_id) VALUES (?, ?, 'pending', ?, 0, ?, ?, ?)`),
  get: db.prepare(`SELECT * FROM jobs WHERE id = ?`),
  updateStatus: db.prepare(`UPDATE jobs SET status = ?, updated_at = ? WHERE id = ?`),
  updateProgress: db.prepare(`UPDATE jobs SET progress = ?, updated_at = ? WHERE id = ?`),
  finish: db.prepare(`UPDATE jobs SET status = 'done', progress = 100, result = ?, finished_at = ?, updated_at = ? WHERE id = ?`),
  fail: db.prepare(`UPDATE jobs SET status = 'error', error = ?, finished_at = ?, updated_at = ? WHERE id = ?`),
  pending: db.prepare(`SELECT * FROM jobs WHERE type = ? AND status = 'pending' ORDER BY created_at LIMIT ?`),
  cleanup: db.prepare(`DELETE FROM jobs WHERE finished_at < ? AND status IN ('done', 'error')`),
  stats: db.prepare(`SELECT status, COUNT(*) as count FROM jobs GROUP BY status`),
  activeCount: db.prepare(`SELECT COUNT(*) as count FROM jobs WHERE status = 'processing'`),
  queueDepth: db.prepare(`SELECT COUNT(*) as count FROM jobs WHERE status = 'pending'`),
};

function generateId(prefix) {
  return `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
}

function addJob(type, payload, userId) {
  const id = generateId(type);
  const now = Date.now();
  stmts.insert.run(id, type, JSON.stringify(payload), now, now, userId != null ? String(userId) : null);
  log.info(`Job added: ${id}`, { type });
  return id;
}

function getJob(id) {
  const row = stmts.get.get(id);
  if (!row) return null;
  row.payload = JSON.parse(row.payload);
  if (row.result) row.result = JSON.parse(row.result);
  return row;
}

function startJob(id) {
  const now = Date.now();
  db.prepare(`UPDATE jobs SET status = 'processing', started_at = ?, updated_at = ? WHERE id = ?`).run(now, now, id);
}

function updateProgress(id, progress) {
  stmts.updateProgress.run(progress, Date.now(), id);
}

function finishJob(id, result) {
  const now = Date.now();
  stmts.finish.run(JSON.stringify(result), now, now, id);
  log.info(`Job done: ${id}`);
}

function failJob(id, error) {
  const now = Date.now();
  stmts.fail.run(String(error).slice(0, 500), now, now, id);
  log.error(`Job failed: ${id}`, { error: String(error).slice(0, 200) });
}

function getPending(type, limit = 5) {
  return stmts.pending.all(type, limit).map(row => {
    row.payload = JSON.parse(row.payload);
    return row;
  });
}

function getStats() {
  const rows = stmts.stats.all();
  const stats = {};
  for (const r of rows) stats[r.status] = r.count;
  return stats;
}

function getActiveCount() {
  return stmts.activeCount.get().count;
}

function getQueueDepth() {
  return stmts.queueDepth.get().count;
}

// Cleanup old finished jobs (older than 1 hour)
function cleanup() {
  const cutoff = Date.now() - 3600000;
  const result = stmts.cleanup.run(cutoff);
  if (result.changes > 0) log.info(`Cleaned up ${result.changes} old jobs`);
}

// Run cleanup every 10 min
setInterval(cleanup, 600000);

// Graceful close
process.on('exit', () => { try { db.close(); } catch {} });

module.exports = {
  addJob,
  getJob,
  startJob,
  updateProgress,
  finishJob,
  failJob,
  getPending,
  getStats,
  getActiveCount,
  getQueueDepth,
  cleanup,
  db,
};
