/**
 * End-to-end integration tests for the audit persistence layer.
 * Same framing as receipts.integration.test.ts: prove the on-disk
 * JSONL round-trip actually works under a scoped cwd.
 */

import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { readFile, rm, mkdtemp } from 'fs/promises'
import { existsSync } from 'fs'
import { tmpdir } from 'os'
import { join } from 'path'
import { runWithCwdOverride } from '../../../utils/cwd.js'
import { appendAuditEntry, createAuditEntry, listAuditEntries, parseAuditJsonl } from '../audit.js'

let scratch: string

beforeEach(async () => {
  scratch = await mkdtemp(join(tmpdir(), 'sandcode-audit-'))
})

afterEach(async () => {
  await rm(scratch, { recursive: true, force: true })
})

describe('audit persistence (integration)', () => {
  it('writes a single audit entry to .sandcode/audit.jsonl', async () => {
    await runWithCwdOverride(scratch, async () => {
      await appendAuditEntry(
        createAuditEntry({
          sessionId: 's',
          toolName: 'Bash',
          input: { command: 'ls' },
          securityMode: false,
        }),
      )
    })

    const path = join(scratch, '.sandcode', 'audit.jsonl')
    expect(existsSync(path)).toBe(true)
    const parsed = parseAuditJsonl(await readFile(path, 'utf-8'))
    expect(parsed).toHaveLength(1)
    expect(parsed[0].tool_name).toBe('Bash')
  })

  it('round-trips many entries, most-recent first on read', async () => {
    await runWithCwdOverride(scratch, async () => {
      for (let i = 0; i < 5; i++) {
        await appendAuditEntry(
          createAuditEntry({
            sessionId: 's',
            toolName: `Tool${i}`,
            input: { i },
            securityMode: i % 2 === 0,
          }),
        )
      }
      const out = await listAuditEntries(10)
      expect(out).toHaveLength(5)
      expect(out[0].tool_name).toBe('Tool4')
      expect(out[4].tool_name).toBe('Tool0')
    })
  })

  it('swallows write errors rather than throwing', async () => {
    const bogusCwd = join(scratch, 'nested', 'missing', 'path')
    await runWithCwdOverride(bogusCwd, async () => {
      await expect(
        appendAuditEntry(
          createAuditEntry({
            sessionId: 's',
            toolName: 'X',
            input: {},
            securityMode: false,
          }),
        ),
      ).resolves.toBeUndefined()
    })
  })

  it('listAuditEntries returns [] when no audit file exists', async () => {
    await runWithCwdOverride(scratch, async () => {
      expect(await listAuditEntries()).toEqual([])
    })
  })

  it('captures security_mode flag as written, not at read time', async () => {
    await runWithCwdOverride(scratch, async () => {
      await appendAuditEntry(
        createAuditEntry({
          sessionId: 's',
          toolName: 'A',
          input: {},
          securityMode: true,
        }),
      )
      await appendAuditEntry(
        createAuditEntry({
          sessionId: 's',
          toolName: 'B',
          input: {},
          securityMode: false,
        }),
      )
      const entries = await listAuditEntries()
      const a = entries.find((e) => e.tool_name === 'A')!
      const b = entries.find((e) => e.tool_name === 'B')!
      expect(a.security_mode).toBe(true)
      expect(b.security_mode).toBe(false)
    })
  })
})
