import {
  Controller,
  Get,
  Query,
  Param,
  Headers,
  UnauthorizedException,
  NotFoundException,
} from '@nestjs/common';
import {
  AuditLogService,
  AuditLogDto,
  PaginatedAuditLogs,
  ActorType,
  AuditResult,
} from '../../application/services/audit-log.service';
import { AdminService } from '../../../application/services/admin.service';

@Controller('audit')
export class AuditController {
  constructor(
    private readonly auditLogService: AuditLogService,
    private readonly adminService: AdminService,
  ) {}

  /**
   * Verify admin authorization
   */
  private async verifyAdmin(authorization: string): Promise<{ id: string; username: string }> {
    if (!authorization?.startsWith('Bearer ')) {
      throw new UnauthorizedException('Missing authorization token');
    }

    const token = authorization.substring(7);
    const result = await this.adminService.verifyToken(token);

    if (!result.valid || !result.admin) {
      throw new UnauthorizedException('Invalid or expired token');
    }

    return { id: result.admin.id, username: result.admin.username };
  }

  /**
   * GET /audit/logs
   * Query audit logs with filters
   */
  @Get('logs')
  async getAuditLogs(
    @Headers('authorization') auth: string,
    @Query('actorType') actorType?: ActorType,
    @Query('actorId') actorId?: string,
    @Query('action') action?: string,
    @Query('entityType') entityType?: string,
    @Query('entityId') entityId?: string,
    @Query('result') result?: AuditResult,
    @Query('startDate') startDate?: string,
    @Query('endDate') endDate?: string,
    @Query('page') page = '1',
    @Query('pageSize') pageSize = '50',
  ): Promise<PaginatedAuditLogs> {
    await this.verifyAdmin(auth);

    return this.auditLogService.queryLogs({
      actorType,
      actorId,
      action,
      entityType,
      entityId,
      result,
      startDate,
      endDate,
      page: parseInt(page, 10),
      pageSize: parseInt(pageSize, 10),
    });
  }

  /**
   * GET /audit/logs/actions
   * Get list of available action types
   * NOTE: This must be defined BEFORE logs/:id to avoid route collision
   */
  @Get('logs/actions')
  async getActionTypes(
    @Headers('authorization') auth: string,
  ): Promise<{ actions: string[] }> {
    await this.verifyAdmin(auth);

    // Common action types
    return {
      actions: [
        'CREATE',
        'UPDATE',
        'DELETE',
        'LOGIN',
        'LOGOUT',
        'PAYMENT',
        'REFUND',
        'EXPORT',
        'IMPORT',
        'DAILY_STATS_AGGREGATION',
        'MONTHLY_REPORT_GENERATION',
      ],
    };
  }

  /**
   * GET /audit/logs/entity-types
   * Get list of entity types
   * NOTE: This must be defined BEFORE logs/:id to avoid route collision
   */
  @Get('logs/entity-types')
  async getEntityTypes(
    @Headers('authorization') auth: string,
  ): Promise<{ entityTypes: string[] }> {
    await this.verifyAdmin(auth);

    return {
      entityTypes: [
        'User',
        'Conversation',
        'Message',
        'Order',
        'Payment',
        'Admin',
        'KnowledgeArticle',
        'Experience',
        'DailyStatistics',
        'MonthlyFinancialReport',
      ],
    };
  }

  /**
   * GET /audit/logs/entity/:entityType/:entityId
   * Get audit history for a specific entity
   */
  @Get('logs/entity/:entityType/:entityId')
  async getEntityAuditHistory(
    @Headers('authorization') auth: string,
    @Param('entityType') entityType: string,
    @Param('entityId') entityId: string,
  ): Promise<AuditLogDto[]> {
    await this.verifyAdmin(auth);
    return this.auditLogService.getEntityHistory(entityType, entityId);
  }

  /**
   * GET /audit/logs/actor/:actorId
   * Get audit history for a specific actor
   */
  @Get('logs/actor/:actorId')
  async getActorAuditHistory(
    @Headers('authorization') auth: string,
    @Param('actorId') actorId: string,
    @Query('page') page = '1',
    @Query('pageSize') pageSize = '50',
  ): Promise<PaginatedAuditLogs> {
    await this.verifyAdmin(auth);

    return this.auditLogService.getActorHistory(
      actorId,
      parseInt(page, 10),
      parseInt(pageSize, 10),
    );
  }

  /**
   * GET /audit/logs/:id
   * Get single audit log detail
   * NOTE: This must be defined LAST to avoid matching "actions", "entity-types", etc. as :id
   */
  @Get('logs/:id')
  async getAuditLogDetail(
    @Headers('authorization') auth: string,
    @Param('id') id: string,
  ): Promise<AuditLogDto> {
    await this.verifyAdmin(auth);

    const log = await this.auditLogService.getLog(id);

    if (!log) {
      throw new NotFoundException('Audit log not found');
    }

    return log;
  }
}
