// @bun
import {
  createCliLogger
} from "./chunk-t993tmz7.js";

// src/utils/sqlite-log-store.ts
import { Database } from "bun:sqlite";
import { mkdirSync } from "fs";
import { join as join2 } from "path";

// src/logs/log-reader.ts
import { existsSync, readdirSync, statSync } from "fs";
import { join } from "path";
function normalizeLevel(type) {
  const lower = type.toLowerCase();
  if (lower === "error")
    return "error";
  if (lower === "warn" || lower === "warning")
    return "warning";
  if (lower === "info" || lower === "stdout" || lower === "stderr" || lower === "log")
    return "info";
  return lower;
}
function findLatestLogFile(agentRoot) {
  const logsDir = join(agentRoot, ".adk", "logs");
  if (!existsSync(logsDir))
    return null;
  try {
    const files = readdirSync(logsDir).filter((f) => f.startsWith("adk-dev-") && f.endsWith(".log")).map((f) => ({
      name: f,
      path: join(logsDir, f),
      mtime: statSync(join(logsDir, f)).mtime.getTime()
    })).sort((a, b) => b.mtime - a.mtime);
    return files.length > 0 ? files[0].path : null;
  } catch {
    return null;
  }
}
function parseLine(line) {
  if (!line.trim())
    return null;
  try {
    const parsed = JSON.parse(line);
    if (parsed.type === "worker_stats")
      return null;
    const msg = parsed.message || (Array.isArray(parsed.args) ? parsed.args.join(" ") : "") || "";
    if (msg.includes("ExperimentalWarning") || msg.includes("punycode"))
      return null;
    return {
      timestamp: parsed.timestamp || new Date().toISOString(),
      type: parsed.type || "info",
      level: normalizeLevel(parsed.type || parsed.level || "info"),
      message: msg,
      raw: line,
      spanId: parsed.spanId,
      traceId: parsed.traceId
    };
  } catch {
    return {
      timestamp: new Date().toISOString(),
      type: "raw",
      level: "raw",
      message: line,
      raw: line
    };
  }
}
function matchesLevel(entry, level) {
  if (!level)
    return true;
  const l = entry.level;
  if (level === "error")
    return l === "error";
  if (level === "warning")
    return l === "error" || l === "warning";
  if (level === "info")
    return l === "error" || l === "warning" || l === "info";
  return true;
}
function matchesSince(entry, since) {
  if (!since)
    return true;
  const ts = new Date(entry.timestamp).getTime();
  return !isNaN(ts) && ts >= since;
}
function filterLogEntries(entries, options) {
  const limit = options.limit ?? 50;
  return entries.filter((entry) => matchesLevel(entry, options.level) && matchesSince(entry, options.since)).slice(-limit);
}

// src/utils/sqlite-log-store.ts
var logger = createCliLogger({ tag: "sqlite-log-store" });
var FLUSH_DELAY_MS = 16;
var FLUSH_MAX_BATCH = 250;
var CHECKPOINT_INTERVAL_MS = 5000;
var SCHEMA = `
CREATE TABLE IF NOT EXISTS logs (
  id         INTEGER PRIMARY KEY AUTOINCREMENT,
  ts         REAL NOT NULL,
  timestamp  TEXT NOT NULL,
  type       TEXT NOT NULL,
  level      TEXT NOT NULL,
  message    TEXT NOT NULL,
  span_id    TEXT,
  trace_id   TEXT,
  raw        TEXT NOT NULL
);

CREATE INDEX IF NOT EXISTS idx_logs_ts ON logs(ts);
CREATE INDEX IF NOT EXISTS idx_logs_level ON logs(level);
CREATE INDEX IF NOT EXISTS idx_logs_trace ON logs(trace_id) WHERE trace_id IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_logs_span ON logs(span_id) WHERE span_id IS NOT NULL;
`;
function levelsFor(level) {
  if (level === "error")
    return ["error"];
  if (level === "warning")
    return ["error", "warning"];
  return ["error", "warning", "info"];
}
function rowToEntry(row) {
  return {
    id: row.id,
    timestamp: row.timestamp,
    type: row.type,
    level: row.level,
    message: row.message,
    raw: row.raw,
    spanId: row.span_id ?? undefined,
    traceId: row.trace_id ?? undefined
  };
}

class SqliteLogStore {
  db = null;
  dbPath;
  logsDir;
  insertStmt = null;
  writeQueue = [];
  flushTimer = null;
  checkpointTimer = null;
  constructor(agentPath) {
    this.logsDir = agentPath ? join2(agentPath, ".adk", "bot", "logs") : process.env.LOG_DIR ?? "logs";
    this.dbPath = join2(this.logsDir, "logs.db");
  }
  getDb() {
    if (this.db)
      return this.db;
    mkdirSync(this.logsDir, { recursive: true });
    try {
      this.db = new Database(this.dbPath);
      this.db.run("PRAGMA journal_mode=WAL");
      this.db.run("PRAGMA synchronous=NORMAL");
      this.db.run("PRAGMA busy_timeout=5000");
      this.db.run("PRAGMA wal_autocheckpoint=0");
      this.db.run(SCHEMA);
      this.insertStmt = this.db.prepare(`
        INSERT INTO logs (ts, timestamp, type, level, message, span_id, trace_id, raw)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?)
      `);
      this.startCheckpointTimer();
      return this.db;
    } catch (err) {
      logger.warn(`Failed to initialize database: ${err instanceof Error ? err.message : String(err)}`);
      return null;
    }
  }
  clear() {
    this.writeQueue = [];
    if (this.flushTimer) {
      clearTimeout(this.flushTimer);
      this.flushTimer = null;
    }
    const db = this.getDb();
    if (!db)
      return;
    db.run("DELETE FROM logs");
  }
  insertLine(line) {
    const entry = parseLine(line);
    if (!entry)
      return;
    this.insertEntry(entry);
  }
  insertEntry(entry) {
    const db = this.getDb();
    if (!db || !this.insertStmt)
      return;
    const parsedTs = Date.parse(entry.timestamp);
    const ts = Number.isNaN(parsedTs) ? Date.now() : parsedTs;
    this.insertStmt.run(ts, entry.timestamp, entry.type, entry.level, entry.message, entry.spanId ?? null, entry.traceId ?? null, entry.raw);
  }
  enqueueLine(line) {
    const entry = parseLine(line);
    if (!entry)
      return;
    this.writeQueue.push(entry);
    this.scheduleFlush();
  }
  scheduleFlush() {
    if (this.writeQueue.length >= FLUSH_MAX_BATCH) {
      this.flush();
      return;
    }
    if (this.flushTimer)
      return;
    this.flushTimer = setTimeout(() => {
      this.flushTimer = null;
      this.flush();
    }, FLUSH_DELAY_MS);
    this.flushTimer.unref?.();
  }
  flush() {
    if (this.writeQueue.length === 0)
      return;
    if (this.flushTimer) {
      clearTimeout(this.flushTimer);
      this.flushTimer = null;
    }
    const batch = this.writeQueue;
    this.writeQueue = [];
    const db = this.getDb();
    if (!db)
      return;
    try {
      db.transaction((entries) => {
        for (const entry of entries) {
          try {
            this.insertEntry(entry);
          } catch (err) {
            logger.warn(`Failed to write log entry: ${err instanceof Error ? err.message : String(err)}`);
          }
        }
      })(batch);
    } catch (err) {
      logger.warn(`Log batch flush failed: ${err instanceof Error ? err.message : String(err)}`);
    }
  }
  startCheckpointTimer() {
    if (this.checkpointTimer)
      return;
    this.checkpointTimer = setInterval(() => {
      try {
        this.db?.run("PRAGMA wal_checkpoint(PASSIVE)");
      } catch {}
    }, CHECKPOINT_INTERVAL_MS);
    this.checkpointTimer.unref?.();
  }
  getRecentLogs(limit = 50) {
    return this.queryLogs({ limit });
  }
  queryLogs(query) {
    this.flush();
    const db = this.getDb();
    if (!db)
      return [];
    const limit = query.limit ?? 50;
    if (limit <= 0)
      return [];
    const where = [];
    const params = [];
    if (query.level) {
      const levels = levelsFor(query.level);
      where.push(`level IN (${levels.map(() => "?").join(",")})`);
      params.push(...levels);
    }
    if (query.since != null) {
      where.push("ts >= ?");
      params.push(query.since);
    }
    const whereSql = where.length > 0 ? `WHERE ${where.join(" AND ")}` : "";
    const rows = db.prepare(`SELECT * FROM (SELECT * FROM logs ${whereSql} ORDER BY id DESC LIMIT ?) ORDER BY id ASC`).all(...params, limit);
    return rows.map(rowToEntry);
  }
  getMaxId() {
    this.flush();
    const db = this.getDb();
    if (!db)
      return 0;
    const row = db.prepare("SELECT MAX(id) as maxId FROM logs").get();
    return row?.maxId ?? 0;
  }
  getLogsAfter(afterId, query = {}) {
    this.flush();
    const db = this.getDb();
    if (!db)
      return [];
    const where = ["id > ?"];
    const params = [afterId];
    if (query.level) {
      const levels = levelsFor(query.level);
      where.push(`level IN (${levels.map(() => "?").join(",")})`);
      params.push(...levels);
    }
    if (query.since != null) {
      where.push("ts >= ?");
      params.push(query.since);
    }
    const rows = db.prepare(`SELECT * FROM logs WHERE ${where.join(" AND ")} ORDER BY id ASC`).all(...params);
    return rows.map(rowToEntry);
  }
  getLogsByTrace(traceId) {
    this.flush();
    const db = this.getDb();
    if (!db)
      return [];
    const rows = db.prepare("SELECT * FROM logs WHERE trace_id = ? ORDER BY id ASC").all(traceId);
    return rows.map(rowToEntry);
  }
  close() {
    if (this.flushTimer) {
      clearTimeout(this.flushTimer);
      this.flushTimer = null;
    }
    if (this.checkpointTimer) {
      clearInterval(this.checkpointTimer);
      this.checkpointTimer = null;
    }
    try {
      this.flush();
      this.db?.run("PRAGMA wal_checkpoint(TRUNCATE)");
    } catch {}
    try {
      this.db?.close();
      this.db = null;
      this.insertStmt = null;
    } catch {}
  }
}

export { findLatestLogFile, filterLogEntries, SqliteLogStore };
