/**
 * traceAuditLog.ts
 *
 * TRACE Audit Log — Deterministic, Code-Generated
 *
 * Mutations and queries for the TRACE audit log.
 * Every entry is generated by CODE, not by the LLM.
 * This is the core trust mechanism: users can read exactly what tools did.
 *
 * The audit log serves as a verifiable truth that could be saved and
 * replayed deterministically — without the LLM's involvement.
 */

import { v } from "convex/values";
import { query, mutation, internalMutation, internalQuery } from "../../_generated/server";

// ============================================================================
// Mutations
// ============================================================================

/**
 * Append a single audit entry to the TRACE audit log.
 * Called by the TRACE orchestrator after each tool execution.
 */
export const appendAuditEntry = internalMutation({
  args: {
    executionId: v.string(),
    executionType: v.union(
      v.literal("swarm"),
      v.literal("tree"),
      v.literal("chat"),
      v.literal("forecast_refresh"),
      v.literal("linkedin_post"),
      v.literal("pipeline_run"),
    ),
    workflowTag: v.optional(v.string()),
    seq: v.number(),
    choiceType: v.union(
      v.literal("gather_info"),
      v.literal("execute_data_op"),
      v.literal("execute_output"),
      v.literal("finalize"),
    ),
    toolName: v.string(),
    toolParams: v.optional(v.any()),
    metadata: v.object({
      rowCount: v.optional(v.number()),
      columnCount: v.optional(v.number()),
      uniqueValues: v.optional(v.any()),
      charCount: v.optional(v.number()),
      wordCount: v.optional(v.number()),
      keyTopics: v.optional(v.array(v.string())),
      errorMessage: v.optional(v.string()),
      durationMs: v.number(),
      success: v.boolean(),
      intendedState: v.optional(v.string()),
      actualState: v.optional(v.string()),
      correctionApplied: v.optional(v.boolean()),
      originalRequest: v.optional(v.string()),
      deliverySummary: v.optional(v.string()),
    }),
    description: v.string(),
  },
  returns: v.id("traceAuditEntries"),
  handler: async (ctx, args) => {
    return await ctx.db.insert("traceAuditEntries", {
      executionId: args.executionId,
      executionType: args.executionType,
      workflowTag: args.workflowTag,
      seq: args.seq,
      timestamp: Date.now(),
      choiceType: args.choiceType,
      toolName: args.toolName,
      toolParams: args.toolParams,
      metadata: args.metadata,
      description: args.description,
      createdAt: Date.now(),
    });
  },
});

/**
 * Append an audit entry (public, for use from actions via ctx.runMutation).
 */
export const appendAuditEntryPublic = mutation({
  args: {
    executionId: v.string(),
    executionType: v.union(
      v.literal("swarm"),
      v.literal("tree"),
      v.literal("chat"),
      v.literal("forecast_refresh"),
      v.literal("linkedin_post"),
      v.literal("pipeline_run"),
    ),
    workflowTag: v.optional(v.string()),
    seq: v.number(),
    choiceType: v.union(
      v.literal("gather_info"),
      v.literal("execute_data_op"),
      v.literal("execute_output"),
      v.literal("finalize"),
    ),
    toolName: v.string(),
    toolParams: v.optional(v.any()),
    metadata: v.object({
      rowCount: v.optional(v.number()),
      columnCount: v.optional(v.number()),
      uniqueValues: v.optional(v.any()),
      charCount: v.optional(v.number()),
      wordCount: v.optional(v.number()),
      keyTopics: v.optional(v.array(v.string())),
      errorMessage: v.optional(v.string()),
      durationMs: v.number(),
      success: v.boolean(),
      intendedState: v.optional(v.string()),
      actualState: v.optional(v.string()),
      correctionApplied: v.optional(v.boolean()),
      originalRequest: v.optional(v.string()),
      deliverySummary: v.optional(v.string()),
    }),
    description: v.string(),
  },
  returns: v.id("traceAuditEntries"),
  handler: async (ctx, args) => {
    return await ctx.db.insert("traceAuditEntries", {
      executionId: args.executionId,
      executionType: args.executionType,
      workflowTag: args.workflowTag,
      seq: args.seq,
      timestamp: Date.now(),
      choiceType: args.choiceType,
      toolName: args.toolName,
      toolParams: args.toolParams,
      metadata: args.metadata,
      description: args.description,
      createdAt: Date.now(),
    });
  },
});

// ============================================================================
// Queries
// ============================================================================

/**
 * Get the full audit log for an execution (swarm, tree, or chat).
 * Returns entries ordered by sequence number.
 */
export const getAuditLog = query({
  args: {
    executionId: v.string(),
  },
  returns: v.array(v.object({
    _id: v.id("traceAuditEntries"),
    _creationTime: v.number(),
    executionId: v.string(),
    executionType: v.union(
      v.literal("swarm"),
      v.literal("tree"),
      v.literal("chat"),
      v.literal("forecast_refresh"),
      v.literal("linkedin_post"),
      v.literal("pipeline_run"),
    ),
    workflowTag: v.optional(v.string()),
    seq: v.number(),
    timestamp: v.number(),
    choiceType: v.union(
      v.literal("gather_info"),
      v.literal("execute_data_op"),
      v.literal("execute_output"),
      v.literal("finalize"),
    ),
    toolName: v.string(),
    toolParams: v.optional(v.any()),
    metadata: v.object({
      rowCount: v.optional(v.number()),
      columnCount: v.optional(v.number()),
      uniqueValues: v.optional(v.any()),
      charCount: v.optional(v.number()),
      wordCount: v.optional(v.number()),
      keyTopics: v.optional(v.array(v.string())),
      errorMessage: v.optional(v.string()),
      durationMs: v.number(),
      success: v.boolean(),
      intendedState: v.optional(v.string()),
      actualState: v.optional(v.string()),
      correctionApplied: v.optional(v.boolean()),
      originalRequest: v.optional(v.string()),
      deliverySummary: v.optional(v.string()),
    }),
    description: v.string(),
    createdAt: v.number(),
  })),
  handler: async (ctx, args) => {
    const entries = await ctx.db
      .query("traceAuditEntries")
      .withIndex("by_execution", (q) => q.eq("executionId", args.executionId))
      .order("asc")
      .collect();
    return entries;
  },
});

/**
 * Internal query for the audit log (used from actions).
 */
export const getAuditLogInternal = internalQuery({
  args: {
    executionId: v.string(),
  },
  returns: v.array(v.object({
    _id: v.id("traceAuditEntries"),
    _creationTime: v.number(),
    executionId: v.string(),
    executionType: v.union(
      v.literal("swarm"),
      v.literal("tree"),
      v.literal("chat"),
      v.literal("forecast_refresh"),
      v.literal("linkedin_post"),
      v.literal("pipeline_run"),
    ),
    workflowTag: v.optional(v.string()),
    seq: v.number(),
    timestamp: v.number(),
    choiceType: v.union(
      v.literal("gather_info"),
      v.literal("execute_data_op"),
      v.literal("execute_output"),
      v.literal("finalize"),
    ),
    toolName: v.string(),
    toolParams: v.optional(v.any()),
    metadata: v.object({
      rowCount: v.optional(v.number()),
      columnCount: v.optional(v.number()),
      uniqueValues: v.optional(v.any()),
      charCount: v.optional(v.number()),
      wordCount: v.optional(v.number()),
      keyTopics: v.optional(v.array(v.string())),
      errorMessage: v.optional(v.string()),
      durationMs: v.number(),
      success: v.boolean(),
      intendedState: v.optional(v.string()),
      actualState: v.optional(v.string()),
      correctionApplied: v.optional(v.boolean()),
      originalRequest: v.optional(v.string()),
      deliverySummary: v.optional(v.string()),
    }),
    description: v.string(),
    createdAt: v.number(),
  })),
  handler: async (ctx, args) => {
    const entries = await ctx.db
      .query("traceAuditEntries")
      .withIndex("by_execution", (q) => q.eq("executionId", args.executionId))
      .order("asc")
      .collect();
    return entries;
  },
});

/**
 * Get audit entries by workflow tag (e.g. "forecast_refresh_2026-02-15").
 * Used by LinkedIn post workflow to build TRACE breadcrumbs.
 */
export const getAuditLogByWorkflowTag = internalQuery({
  args: {
    workflowTag: v.string(),
  },
  handler: async (ctx, args) => {
    return ctx.db
      .query("traceAuditEntries")
      .withIndex("by_workflow_tag", (q) => q.eq("workflowTag", args.workflowTag))
      .order("asc")
      .collect();
  },
});

/**
 * Get a compact summary of the audit log for UI display.
 * Returns key stats without the full entry details.
 */
export const getAuditSummary = query({
  args: {
    executionId: v.string(),
  },
  returns: v.object({
    totalSteps: v.number(),
    gatherInfoSteps: v.number(),
    dataOpSteps: v.number(),
    outputSteps: v.number(),
    selfCorrections: v.number(),
    failures: v.number(),
    totalDurationMs: v.number(),
    toolsUsed: v.array(v.string()),
    hasFinalized: v.boolean(),
  }),
  handler: async (ctx, args) => {
    const entries = await ctx.db
      .query("traceAuditEntries")
      .withIndex("by_execution", (q) => q.eq("executionId", args.executionId))
      .order("asc")
      .collect();

    const toolsUsed = [...new Set(entries.map((e) => e.toolName))];

    return {
      totalSteps: entries.length,
      gatherInfoSteps: entries.filter((e) => e.choiceType === "gather_info").length,
      dataOpSteps: entries.filter((e) => e.choiceType === "execute_data_op").length,
      outputSteps: entries.filter((e) => e.choiceType === "execute_output").length,
      selfCorrections: entries.filter((e) => e.metadata.correctionApplied).length,
      failures: entries.filter((e) => !e.metadata.success).length,
      totalDurationMs: entries.reduce((sum, e) => sum + e.metadata.durationMs, 0),
      toolsUsed,
      hasFinalized: entries.some((e) => e.choiceType === "finalize"),
    };
  },
});
