import { Controller, Get, Post, Query, UseGuards } from '@nestjs/common'
import { JwtAuthGuard } from '../auth/jwt-auth.guard.js'
import { OperatorGuard } from '../auth/operator.guard.js'
import { ArchiveService } from '../cold/archive.service.js'
import { ListAuditDto } from './dto/list-audit.dto.js'
import { AuditService } from './audit.service.js'
import { CheckpointService } from './checkpoint.service.js'
import { AuditVerifier } from './verifier.service.js'

// Read-only. There is intentionally no POST/PATCH/DELETE on /audit itself
// — entries are written by AuditService.record(), called from every
// mutation in other modules. Operator-only because the trail is sensitive.
//
// Phase 3 surfaces:
//   GET /audit/verify             — walks chain + validates checkpoint sigs
//   GET /audit/checkpoint/latest  — current "last verified" anchor for UI
//   POST /audit/checkpoint        — force a fresh checkpoint
// Phase 4 surfaces:
//   GET /audit/archives           — list archive batches (most recent first)
//   POST /audit/archive/run       — manually trigger an archive run with
//                                  override=true so the retention window
//                                  is bypassed (used from the operator UI
//                                  to exercise the cold-storage path in dev)
@Controller('audit')
@UseGuards(JwtAuthGuard, OperatorGuard)
export class AuditController {
  constructor(
    private readonly audit: AuditService,
    private readonly checkpoints: CheckpointService,
    private readonly verifier: AuditVerifier,
    private readonly archives: ArchiveService,
  ) {}

  @Get()
  list(@Query() q: ListAuditDto) {
    return this.audit.list({
      since: q.since ? new Date(q.since) : undefined,
      until: q.until ? new Date(q.until) : undefined,
      before: q.before ? new Date(q.before) : undefined,
      action: q.action,
      tenantSlug: q.tenantSlug,
      partnerSlug: q.partnerSlug,
      actorEmail: q.actorEmail,
      outcome: q.outcome,
      q: q.q,
      limit: q.limit,
    })
  }

  @Get('verify')
  async verify() {
    const base = await this.verifier.verify()
    // Augment with tier boundary so the UI can show "events before X are
    // archived, events from X+ are queryable here".
    const [oldestHotSeq, highestArchivedSeq] = await Promise.all([
      this.archives.oldestHotSeq(),
      this.archives.highestArchivedSeq(),
    ])
    return { ...base, oldestHotSeq, highestArchivedSeq }
  }

  @Get('checkpoint/latest')
  async latestCheckpoint() {
    const cp = await this.checkpoints.latest()
    if (!cp) return { at: null, headSeq: null, headHash: null }
    return { at: cp.at, headSeq: cp.headSeq, headHash: cp.headHash, reason: cp.reason }
  }

  @Post('checkpoint')
  forceCheckpoint() {
    return this.checkpoints.tryWrite('manual')
  }

  @Get('archives')
  async listArchives() {
    const batches = await this.archives.listBatches(100)
    return batches.map((b) => ({
      _id: b._id,
      archivedAt: b.archivedAt,
      startSeq: b.startSeq,
      endSeq: b.endSeq,
      eventCount: b.eventCount,
      manifestSha256: b.manifestSha256,
      jsonlKey: b.jsonlKey,
      manifestKey: b.manifestKey,
      bytesUncompressed: b.bytesUncompressed,
    }))
  }

  // `override=true` (the only mode we expose to the UI today) bypasses the
  // 90-day retention check and archives everything older than now. This is
  // how operators exercise the cold-storage path in dev without 3-month-old
  // events. Production should disable this query param via a config flag
  // before going live; for now it's gated behind OperatorGuard.
  @Post('archive/run')
  async runArchive(@Query('override') override?: string) {
    return this.archives.runOnce({ override: override === 'true' })
  }
}
