import {
  Body,
  Controller,
  Delete,
  Get,
  HttpCode,
  HttpStatus,
  Post,
  Query,
  UseGuards,
} from '@nestjs/common';
import { User } from '../auth/decorators/user.decorator';
import { AuthenticatedUser } from '../auth/interfaces/jwt-payload.interface';
import { AllowAuth } from '../common/decorators/allow-auth.decorator';
import { RequireScopes } from '../common/decorators/require-scopes.decorator';
import { ServiceCredentialGuard } from '../common/guards/service-credential/service-credential.guard';
import { AuditEventsService } from './audit-events.service';
import { CreateAhaRuleVersionDto } from './dto/create-aha-rule-version.dto';
import { CreateAuditEventsBatchDto } from './dto/create-audit-event.dto';
import { QueryAhaProgressDto } from './dto/query-aha-progress.dto';
import {
  AhaMetricsQuery,
  AuditEventFilters,
} from './dto/query-audit-events.dto';
import { AuditEventsFeatureGuard } from './guards/audit-events-feature.guard';
import { AuditEventsRateLimitGuard } from './guards/audit-events-rate-limit.guard';

@Controller('audit-events')
export class AuditEventsController {
  constructor(private readonly auditEventsService: AuditEventsService) {}

  @Post()
  @AllowAuth(['service_key', 'user_jwt', 'client_jwt'])
  @RequireScopes('bff:audit-events:write')
  @UseGuards(
    AuditEventsFeatureGuard,
    AuditEventsRateLimitGuard,
    ServiceCredentialGuard,
  )
  @HttpCode(HttpStatus.ACCEPTED)
  create(
    @Body() dto: CreateAuditEventsBatchDto,
    @User() user?: AuthenticatedUser,
  ) {
    return this.auditEventsService.createBatch(dto.events ?? [], user);
  }

  @Get()
  @AllowAuth(['service_key'])
  @RequireScopes('bff:audit-events:read')
  @UseGuards(AuditEventsFeatureGuard, ServiceCredentialGuard)
  findAll(@Query() query: Record<string, string>) {
    return this.auditEventsService.findAll(this.parseFilters(query));
  }

  @Get('rollups')
  @AllowAuth(['service_key'])
  @RequireScopes('bff:audit-events:read')
  @UseGuards(AuditEventsFeatureGuard, ServiceCredentialGuard)
  findRollups(@Query() query: Record<string, string>) {
    return this.auditEventsService.findRollups(this.parseFilters(query));
  }

  @Get('aha-metrics')
  @AllowAuth(['service_key'])
  @RequireScopes('bff:audit-events:read')
  @UseGuards(AuditEventsFeatureGuard, ServiceCredentialGuard)
  getAhaMetrics(@Query() query: Record<string, string>) {
    return this.auditEventsService.getAhaMetrics(this.parseAhaQuery(query));
  }

  @Get('aha-rules/active')
  @AllowAuth(['service_key'])
  @RequireScopes('bff:audit-events:read')
  @UseGuards(AuditEventsFeatureGuard, ServiceCredentialGuard)
  getActiveAhaRule() {
    return this.auditEventsService.getActiveAhaRule();
  }

  @Get('aha-rules')
  @AllowAuth(['service_key'])
  @RequireScopes('bff:audit-events:read')
  @UseGuards(AuditEventsFeatureGuard, ServiceCredentialGuard)
  listAhaRuleVersions() {
    return this.auditEventsService.listAhaRuleVersions();
  }

  @Post('aha-rules')
  @AllowAuth(['service_key'])
  @RequireScopes('bff:audit-events:admin')
  @UseGuards(AuditEventsFeatureGuard, ServiceCredentialGuard)
  createAhaRuleVersion(
    @Body() dto: CreateAhaRuleVersionDto,
    @User() user?: AuthenticatedUser,
  ) {
    return this.auditEventsService.createAhaRuleVersion(dto, user);
  }

  @Get('aha-progress')
  @AllowAuth(['service_key'])
  @RequireScopes('bff:audit-events:read')
  @UseGuards(AuditEventsFeatureGuard, ServiceCredentialGuard)
  listAhaProgress(@Query() query: Record<string, string>) {
    return this.auditEventsService.listAhaProgress(
      this.parseAhaProgressQuery(query),
    );
  }

  @Get('aha-rules/snippet')
  @AllowAuth(['service_key'])
  @RequireScopes('bff:audit-events:read')
  @UseGuards(AuditEventsFeatureGuard, ServiceCredentialGuard)
  getAhaRuleSnippet() {
    return this.auditEventsService.getAhaRuleSnippet();
  }

  @Get('rollups/preview')
  @AllowAuth(['service_key'])
  @RequireScopes('bff:audit-events:read')
  @UseGuards(AuditEventsFeatureGuard, ServiceCredentialGuard)
  previewRollups(@Query() query: Record<string, string>) {
    return this.auditEventsService.previewRollups(this.parseFilters(query));
  }

  @Post('rollups/run')
  @AllowAuth(['service_key'])
  @RequireScopes('bff:audit-events:admin')
  @UseGuards(AuditEventsFeatureGuard, ServiceCredentialGuard)
  runRollups(@Query() query: Record<string, string>) {
    return this.auditEventsService.runRollups(this.parseFilters(query));
  }

  @Delete('rollups/prune')
  @AllowAuth(['service_key'])
  @RequireScopes('bff:audit-events:admin')
  @UseGuards(AuditEventsFeatureGuard, ServiceCredentialGuard)
  pruneRolledUpEvents(@Query() query: Record<string, string>) {
    return this.auditEventsService.pruneRolledUpEvents(
      this.parseFilters(query),
    );
  }

  @Delete('rollups')
  @AllowAuth(['service_key'])
  @RequireScopes('bff:audit-events:admin')
  @UseGuards(AuditEventsFeatureGuard, ServiceCredentialGuard)
  deleteRollups(@Query() query: Record<string, string>) {
    return this.auditEventsService.deleteRollups(this.parseFilters(query));
  }

  @Delete('rollups/delete-selected')
  @AllowAuth(['service_key'])
  @RequireScopes('bff:audit-events:admin')
  @UseGuards(AuditEventsFeatureGuard, ServiceCredentialGuard)
  deleteSelectedRollups(@Body('rollup_keys') rollupKeys: string[]) {
    return this.auditEventsService.deleteSelectedRollups(rollupKeys);
  }

  @Delete('delete-selected')
  @AllowAuth(['service_key'])
  @RequireScopes('bff:audit-events:admin')
  @UseGuards(AuditEventsFeatureGuard, ServiceCredentialGuard)
  deleteSelectedAuditEvents(@Body('event_ids') eventIds: string[]) {
    return this.auditEventsService.deleteSelectedAuditEvents(eventIds);
  }

  @Delete()
  @AllowAuth(['service_key'])
  @RequireScopes('bff:audit-events:admin')
  @UseGuards(AuditEventsFeatureGuard, ServiceCredentialGuard)
  deleteAuditEvents(@Query() query: Record<string, string>) {
    return this.auditEventsService.deleteAuditEvents(this.parseFilters(query));
  }

  private parseFilters(query: Record<string, string>): AuditEventFilters {
    const filters: AuditEventFilters = {};

    if (query.actor_id) filters.actor_id = query.actor_id;
    if (
      query.actor_role === 'advisor' ||
      query.actor_role === 'client' ||
      query.actor_role === 'unknown'
    ) {
      filters.actor_role = query.actor_role;
    }
    if (query.client_uuid) filters.client_uuid = query.client_uuid;
    if (query.event_name) filters.event_name = query.event_name;
    if (query.session_id) filters.session_id = query.session_id;
    if (query.correlation_id) filters.correlation_id = query.correlation_id;
    if (query.limit) filters.limit = Number(query.limit);
    if (query.offset) filters.offset = Number(query.offset);

    return {
      ...filters,
      ...this.parseAhaQuery(query),
    };
  }

  private parseAhaQuery(query: Record<string, string>): AhaMetricsQuery {
    const parsed: AhaMetricsQuery = {};

    if (query.actor_id) {
      parsed.actor_id = query.actor_id;
    }

    if (query.startDate) {
      const startDate = new Date(query.startDate);
      if (!Number.isNaN(startDate.getTime())) {
        parsed.startDate = startDate;
      }
    }

    if (query.endDate) {
      const endDate = new Date(query.endDate);
      if (!Number.isNaN(endDate.getTime())) {
        parsed.endDate = endDate;
      }
    }

    if (query.rule_version) {
      parsed.rule_version = query.rule_version;
    }

    return parsed;
  }

  private parseAhaProgressQuery(
    query: Record<string, string>,
  ): QueryAhaProgressDto {
    const parsed: QueryAhaProgressDto = {};

    if (query.actor_id) parsed.actor_id = query.actor_id;
    if (query.actor_role === 'advisor') parsed.actor_role = query.actor_role;
    if (query.rule_version) parsed.rule_version = query.rule_version;
    if (query.aha_reached === 'true') parsed.aha_reached = true;
    if (query.limit) parsed.limit = Number(query.limit);
    if (query.offset) parsed.offset = Number(query.offset);

    return parsed;
  }
}
