import { createHash } from "node:crypto";

export type GoogleToolAuditStatus = "ok" | "failed" | "rejected" | "timeout" | "skipped";

export type GoogleToolLayer = "fcop_core" | "workspace" | "vision";

export type GoogleToolAuditEntry = {
  ts: string;
  agentId: string;
  toolName: string;
  ok: boolean;
  durationMs?: number;
  errorCode?: string;
  summary?: string;
  trace_id?: string;
  run_id?: string;
  session_id?: string;
  task_id?: string;
  role?: string;
  tool?: string;
  tool_layer?: GoogleToolLayer;
  args_hash?: string;
  started_at?: string;
  finished_at?: string;
  status?: GoogleToolAuditStatus;
  turn_index?: number;
};

export function hashGoogleToolArgs(args: Record<string, unknown>): string {
  const stable = JSON.stringify(args, Object.keys(args).sort());
  return createHash("sha256").update(stable).digest("hex").slice(0, 16);
}

export function classifyGoogleToolLayer(toolName: string): GoogleToolLayer {
  if (toolName === "vision.inspect_attachment") return "vision";
  if (
    toolName === "read_file" ||
    toolName === "grep_files" ||
    toolName === "list_dir" ||
    toolName === "write_file" ||
    toolName === "web_search" ||
    toolName === "web_extract" ||
    toolName === "web_research"
    || toolName === "skill_search"
    || toolName === "skill_learn"
    || toolName === "skill_publish"
  ) {
    return "workspace";
  }
  return "fcop_core";
}

export class GoogleToolAuditLogger {
  readonly #entries: GoogleToolAuditEntry[] = [];
  readonly #maxEntries: number;

  constructor(opts?: { maxEntries?: number }) {
    this.#maxEntries = opts?.maxEntries ?? 500;
  }

  log(entry: Omit<GoogleToolAuditEntry, "ts"> & { ts?: string }): void {
    const row: GoogleToolAuditEntry = {
      ts: entry.ts ?? new Date().toISOString(),
      agentId: entry.agentId,
      toolName: entry.toolName,
      ok: entry.ok,
      durationMs: entry.durationMs,
      errorCode: entry.errorCode,
      summary: entry.summary,
      trace_id: entry.trace_id,
      run_id: entry.run_id,
      session_id: entry.session_id,
      task_id: entry.task_id,
      role: entry.role,
      tool: entry.tool ?? entry.toolName,
      tool_layer: entry.tool_layer,
      args_hash: entry.args_hash,
      started_at: entry.started_at,
      finished_at: entry.finished_at,
      status: entry.status,
      turn_index: entry.turn_index,
    };
    this.#entries.push(row);
    if (this.#entries.length > this.#maxEntries) {
      this.#entries.shift();
    }

    const status = row.status ?? (row.ok ? "ok" : "failed");
    console.log(
      `[GoogleToolAudit] ${row.toolName} status=${status} layer=${row.tool_layer ?? "?"} ` +
        `agent=${row.agentId} task=${row.task_id ?? "-"} turn=${row.turn_index ?? "-"} ` +
        `ms=${row.durationMs ?? "-"} code=${row.errorCode ?? "-"}`,
    );
  }

  getEntries(): readonly GoogleToolAuditEntry[] {
    return this.#entries;
  }

  lastEntry(toolName?: string): GoogleToolAuditEntry | undefined {
    if (!toolName) {
      return this.#entries[this.#entries.length - 1];
    }
    for (let i = this.#entries.length - 1; i >= 0; i -= 1) {
      const e = this.#entries[i]!;
      if (e.toolName === toolName) return e;
    }
    return undefined;
  }
}
