import * as fs from 'fs';
import * as path from 'path';
import Database from '../sqlite.js';
import { getUsageDbPath, getSecretsDbPath, getAnalyticsDir } from '../state.js';
import { localMachineId } from '../session/origin-machine.js';
export const USAGE_KINDS = [
    'secret',
    'agent',
    'skill',
    'plugin',
    'browser',
    'computer',
];
const EVENT_RETENTION_MS = 90 * 24 * 60 * 60 * 1000;
const SCHEMA = `
CREATE TABLE IF NOT EXISTS usage_events (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  ts TEXT NOT NULL,
  kind TEXT NOT NULL,
  name TEXT NOT NULL,
  event TEXT NOT NULL,
  agent TEXT,
  session_id TEXT,
  machine TEXT,
  actor TEXT,
  source TEXT,
  status TEXT,
  meta_json TEXT
);
CREATE INDEX IF NOT EXISTS idx_analytics_usage_ts ON usage_events(ts DESC);
CREATE INDEX IF NOT EXISTS idx_analytics_usage_kind_ts ON usage_events(kind, ts DESC);
CREATE INDEX IF NOT EXISTS idx_analytics_usage_kind_name ON usage_events(kind, name);
CREATE INDEX IF NOT EXISTS idx_analytics_usage_kind_event ON usage_events(kind, event);
CREATE INDEX IF NOT EXISTS idx_analytics_usage_machine_ts ON usage_events(machine, ts DESC);
CREATE INDEX IF NOT EXISTS idx_analytics_usage_session ON usage_events(session_id);
CREATE TABLE IF NOT EXISTS meta (
  key TEXT PRIMARY KEY,
  value TEXT NOT NULL
);
`;
let cached = null;
function isDisabled() {
    const v = process.env.AGENTS_NO_USAGE_TRACK;
    return v === '1' || v === 'true';
}
function open() {
    if (isDisabled())
        return null;
    const dbPath = getUsageDbPath();
    if (cached && cached.path === dbPath)
        return cached.db;
    if (cached) {
        try {
            cached.db.close();
        }
        catch { /* ignore */ }
        cached = null;
    }
    try {
        fs.mkdirSync(path.dirname(dbPath), { recursive: true, mode: 0o700 });
        const db = new Database(dbPath);
        db.pragma('journal_mode = WAL');
        db.pragma('busy_timeout = 2000');
        db.exec(SCHEMA);
        try {
            db.prepare(`DELETE FROM usage_events WHERE ts < ?`).run(new Date(Date.now() - EVENT_RETENTION_MS).toISOString());
        }
        catch { /* prune best-effort */ }
        migrateSecretsUsageOnce(db);
        cached = { path: dbPath, db };
        return db;
    }
    catch {
        return null;
    }
}
function migrateSecretsUsageOnce(db) {
    try {
        const done = db.prepare(`SELECT value FROM meta WHERE key = 'migrate_secrets_v1'`).get();
        if (done?.value === '1')
            return;
        const secretsPath = getSecretsDbPath();
        if (fs.existsSync(secretsPath)) {
            const legacy = new Database(secretsPath);
            try {
                const rows = legacy.prepare(`SELECT ts, bundle, event, agent, host, source, status, key_count FROM usage_events`).all();
                const insert = db.prepare(`INSERT INTO usage_events (ts, kind, name, event, agent, session_id, machine, actor, source, status, meta_json)
           VALUES (?, 'secret', ?, ?, ?, NULL, ?, NULL, ?, ?, ?)`);
                const machine = localMachineId();
                const txn = db.transaction((items) => {
                    for (const r of items) {
                        if (!r.bundle)
                            continue;
                        const meta = r.key_count != null ? JSON.stringify({ keyCount: r.key_count, host: r.host }) : (r.host ? JSON.stringify({ host: r.host }) : null);
                        insert.run(r.ts, r.bundle, r.event, r.agent, machine, r.source, r.status, meta);
                    }
                });
                txn(rows);
            }
            finally {
                try {
                    legacy.close();
                }
                catch { /* ignore */ }
            }
        }
        db.prepare(`INSERT OR REPLACE INTO meta(key, value) VALUES ('migrate_secrets_v1', '1')`).run();
    }
    catch {
        /* migrate is best-effort */
    }
}
export function recordUsage(p) {
    if (isDisabled())
        return;
    if (!p.kind || !p.name || !p.event)
        return;
    const db = open();
    if (!db)
        return;
    try {
        db.prepare(`INSERT INTO usage_events (ts, kind, name, event, agent, session_id, machine, actor, source, status, meta_json)
       VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(p.ts ?? new Date().toISOString(), p.kind, p.name, p.event, p.agent ?? null, p.sessionId ?? null, p.machine ?? localMachineId(), p.actor ?? null, p.source ?? null, p.status ?? 'success', p.meta != null ? JSON.stringify(p.meta) : null);
    }
    catch {
        /* telemetry must never break callers */
    }
}
export function usageDbPath() {
    return getUsageDbPath();
}
export function analyticsDir() {
    return getAnalyticsDir();
}
export function listUsageKindsWithData(sinceIso) {
    const db = open();
    if (!db)
        return [];
    try {
        const rows = db.prepare(`SELECT DISTINCT kind FROM usage_events WHERE ts >= ?`).all(sinceIso);
        return rows.map((r) => r.kind).filter((k) => USAGE_KINDS.includes(k));
    }
    catch {
        return [];
    }
}
export function countUsage(opts) {
    const db = open();
    if (!db)
        return 0;
    try {
        const clauses = ['ts >= ?'];
        const args = [opts.sinceIso];
        if (opts.kind) {
            clauses.push('kind = ?');
            args.push(opts.kind);
        }
        if (opts.name) {
            clauses.push('name = ?');
            args.push(opts.name);
        }
        if (opts.event) {
            clauses.push('event = ?');
            args.push(opts.event);
        }
        const row = db.prepare(`SELECT COUNT(*) AS n FROM usage_events WHERE ${clauses.join(' AND ')}`).get(...args);
        return row?.n ?? 0;
    }
    catch {
        return 0;
    }
}
export function queryUsage(opts) {
    const db = open();
    if (!db)
        return [];
    try {
        const clauses = ['ts >= ?'];
        const args = [opts.sinceIso];
        if (opts.kind) {
            clauses.push('kind = ?');
            args.push(opts.kind);
        }
        if (opts.name) {
            clauses.push('name = ?');
            args.push(opts.name);
        }
        if (opts.event) {
            clauses.push('event = ?');
            args.push(opts.event);
        }
        const limit = opts.limit && opts.limit > 0 ? opts.limit : 100;
        args.push(limit);
        const rows = db.prepare(`SELECT ts, kind, name, event, agent, session_id AS sessionId, machine, actor, source, status, meta_json AS metaJson
         FROM usage_events WHERE ${clauses.join(' AND ')}
         ORDER BY ts DESC, id DESC LIMIT ?`).all(...args);
        return rows;
    }
    catch {
        return [];
    }
}
export function topNamesByKind(kind, sinceIso, limit = 20) {
    const db = open();
    if (!db)
        return [];
    try {
        return db.prepare(`SELECT name, COUNT(*) AS n, MAX(ts) AS last
         FROM usage_events WHERE kind = ? AND ts >= ?
         GROUP BY name ORDER BY n DESC LIMIT ?`).all(kind, sinceIso, limit);
    }
    catch {
        return [];
    }
}
export function kindMix(sinceIso) {
    const db = open();
    if (!db)
        return [];
    try {
        return db.prepare(`SELECT kind, COUNT(*) AS n FROM usage_events WHERE ts >= ? GROUP BY kind ORDER BY n DESC`).all(sinceIso);
    }
    catch {
        return [];
    }
}
export function getSecretBundleRollup(bundle) {
    const db = open();
    if (!db)
        return [];
    try {
        return db.prepare(`SELECT event, COUNT(*) AS n, MAX(ts) AS last, MIN(ts) AS first
         FROM usage_events WHERE kind = 'secret' AND name = ? GROUP BY event`).all(bundle);
    }
    catch {
        return [];
    }
}
export function getSecretBundleAgents(bundle) {
    const db = open();
    if (!db)
        return [];
    try {
        return db.prepare(`SELECT agent, COUNT(*) AS n FROM usage_events
         WHERE kind = 'secret' AND name = ? AND agent IS NOT NULL
         GROUP BY agent ORDER BY n DESC`).all(bundle);
    }
    catch {
        return [];
    }
}
export function getAllSecretBundleRollups() {
    const db = open();
    if (!db)
        return [];
    try {
        return db.prepare(`SELECT name, event, COUNT(*) AS n, MAX(ts) AS last, MIN(ts) AS first
         FROM usage_events WHERE kind = 'secret' GROUP BY name, event`).all();
    }
    catch {
        return [];
    }
}
export function getSecretHistory(bundle, limit = 20) {
    const db = open();
    if (!db)
        return [];
    try {
        const sql = bundle
            ? `SELECT ts, name AS bundle, event, agent, source, status, meta_json
           FROM usage_events WHERE kind = 'secret' AND name = ? ORDER BY ts DESC, id DESC LIMIT ?`
            : `SELECT ts, name AS bundle, event, agent, source, status, meta_json
           FROM usage_events WHERE kind = 'secret' ORDER BY ts DESC, id DESC LIMIT ?`;
        const rows = (bundle ? db.prepare(sql).all(bundle, limit) : db.prepare(sql).all(limit));
        return rows.map((r) => {
            let host = null;
            let keyCount = null;
            if (r.meta_json) {
                try {
                    const m = JSON.parse(r.meta_json);
                    host = m.host ?? null;
                    keyCount = typeof m.keyCount === 'number' ? m.keyCount : null;
                }
                catch { /* ignore */ }
            }
            return { ts: r.ts, bundle: r.bundle, event: r.event, agent: r.agent, host, source: r.source, status: r.status, keyCount };
        });
    }
    catch {
        return [];
    }
}
export function closeUsageDb() {
    if (cached) {
        try {
            cached.db.close();
        }
        catch { /* ignore */ }
        cached = null;
    }
}
