// Audit Log Service
// Provides immutable audit trail for all capability toggles and policy decisions

import { v4 as uuidv4 } from 'uuid';
import prisma from '@/shared/database/prisma';
import { DbisError, ErrorCode } from '@/shared/types';
import { logger } from '@/infrastructure/monitoring/logger';
import { ToggleAuditLog } from '@/shared/solacenet/types';

export interface AuditLogQuery {
  capabilityId?: string;
  actor?: string;
  action?: string;
  fromDate?: Date;
  toDate?: Date;
  limit?: number;
  offset?: number;
}

export class AuditLogService {
  /**
   * Log a toggle action
   */
  async logToggle(
    actor: string,
    action: 'enabled' | 'disabled' | 'suspended' | 'drain' | 'kill_switch',
    capabilityId: string,
    beforeState: string | null,
    afterState: string,
    scope?: Record<string, unknown>,
    reason?: string,
    ticket?: string,
    metadata?: Record<string, unknown>
  ): Promise<ToggleAuditLog> {
    const auditLog = await prisma.solacenet_toggle_audit_log.create({
      data: {
        id: uuidv4(),
        actor,
        action,
        capabilityId,
        beforeState,
        afterState,
        scope: scope || null,
        reason: reason || null,
        ticket: ticket || null,
        metadata: metadata || null,
      },
      include: {
        capability: true,
      },
    });

    logger.info(`Toggle audit log created`, {
      id: auditLog.id,
      actor,
      action,
      capabilityId,
      beforeState,
      afterState,
    });

    return this.mapToToggleAuditLog(auditLog);
  }

  /**
   * Query toggle audit logs
   */
  async queryToggleLogs(query: AuditLogQuery): Promise<ToggleAuditLog[]> {
    const where: any = {};

    if (query.capabilityId) {
      where.capabilityId = query.capabilityId;
    }

    if (query.actor) {
      where.actor = query.actor;
    }

    if (query.action) {
      where.action = query.action;
    }

    if (query.fromDate || query.toDate) {
      where.timestamp = {};
      if (query.fromDate) {
        where.timestamp.gte = query.fromDate;
      }
      if (query.toDate) {
        where.timestamp.lte = query.toDate;
      }
    }

    const logs = await prisma.solacenet_toggle_audit_log.findMany({
      where,
      orderBy: {
        timestamp: 'desc',
      },
      take: query.limit || 100,
      skip: query.offset || 0,
      include: {
        capability: true,
      },
    });

    return logs.map(this.mapToToggleAuditLog);
  }

  /**
   * Get a specific audit log entry
   */
  async getAuditLog(id: string): Promise<ToggleAuditLog | null> {
    const log = await prisma.solacenet_toggle_audit_log.findUnique({
      where: { id },
      include: {
        capability: true,
      },
    });

    if (!log) {
      return null;
    }

    return this.mapToToggleAuditLog(log);
  }

  /**
   * Query policy decision logs (if we decide to log decisions separately)
   * For now, decisions are logged as part of the toggle audit log
   */
  async queryDecisionLogs(query: AuditLogQuery): Promise<ToggleAuditLog[]> {
    // Filter for decision-related actions
    return this.queryToggleLogs({
      ...query,
      action: query.action || 'kill_switch', // Adjust based on what actions represent decisions
    });
  }

  /**
   * Map Prisma model to ToggleAuditLog type
   */
  private mapToToggleAuditLog(log: {
    id: string;
    actor: string;
    action: string;
    capabilityId: string;
    beforeState: string | null;
    afterState: string;
    scope: unknown;
    reason: string | null;
    ticket: string | null;
    metadata: unknown;
    timestamp: Date;
  }): ToggleAuditLog {
    return {
      id: log.id,
      actor: log.actor,
      action: log.action as 'enabled' | 'disabled' | 'suspended' | 'drain' | 'kill_switch',
      capabilityId: log.capabilityId,
      beforeState: log.beforeState || undefined,
      afterState: log.afterState,
      scope: log.scope as Record<string, unknown> | undefined,
      reason: log.reason || undefined,
      ticket: log.ticket || undefined,
      metadata: log.metadata as Record<string, unknown> | undefined,
      timestamp: log.timestamp,
    };
  }
}

export const auditLogService = new AuditLogService();
