import { Controller, Get, Post, Body, UseGuards, HttpException, HttpStatus, Logger, ValidationPipe } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBody } from '@nestjs/swagger';
import { BreachCheckService } from './breach-check.service';
import { JwtAuthGuard } from 'common/guards/jwt-auth.guard';
import { RateLimit } from 'common/decorators/rate-limit.decorator';
import { EmailCheckDto, PasswordCheckDto, PhoneCheckDto } from './dto/breach-check.dto';
import { PermissionsGuard } from 'common/guards/ppermissions.guard';
import { Permissions } from 'common/decorators/permissions.decorator';
import { FeatureEnum } from 'common/enum/Permissions.enum';
import { RolesGuard } from 'common/guards/roles.guard';
import { Roles } from 'common/decorators/role.decorator';
import { UserRole } from 'common/enum/UserRole.enum';

@ApiTags('breach-check')
@Controller({ path: 'breach-check', version: '1' })
@UseGuards(JwtAuthGuard, RolesGuard, PermissionsGuard)
export class BreachCheckController {
  private readonly logger = new Logger(BreachCheckController.name);

  constructor(private readonly breachCheckService: BreachCheckService) {}

  @Post('email')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN, UserRole.CLIENT, UserRole.USER)
  // @Permissions(FeatureEnum.BC_EMAIL_CHECK)
  @ApiOperation({ summary: 'Check if an email address appears in any data breaches' })
  @ApiBody({ type: EmailCheckDto })
  @ApiResponse({
    status: 200,
    description: 'Results of the email breach check',
    schema: {
      type: 'object',
      properties: {
        found: { type: 'boolean', example: true },
        breaches: {
          type: 'array',
          items: {
            type: 'object',
            properties: {
              id: { type: 'number', example: 1 },
              source: { type: 'string', example: 'LinkedIn 2021' },
              date: { type: 'string', format: 'date-time', example: '2023-01-15T12:30:45.000Z' },
            },
          },
        },
      },
    },
  })
  @ApiResponse({ status: 400, description: 'Bad request or invalid email' })
  @ApiResponse({ status: 429, description: 'Too many requests' })
  @RateLimit({
    message: 'Too many requests, please try again later',
    statusCode: HttpStatus.TOO_MANY_REQUESTS,
    headers: true,
    max: 20,
    windowMs: 60 * 1000,
  }) // 20 requests per minute
  async checkEmail(@Body(new ValidationPipe({ transform: true })) emailDto: EmailCheckDto) {
    try {
      this.logger.log(`Checking email: ${this.maskEmail(emailDto.email)}`);
      return await this.breachCheckService.checkEmailBreaches(emailDto.email);
    } catch (error) {
      if (error instanceof HttpException) {
        throw error;
      }
      this.logger.error(`Error in email check: ${error.message}`);
      throw new HttpException('Failed to check email', HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @Post('password')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN, UserRole.CLIENT, UserRole.USER)
  // @Permissions(FeatureEnum.BC_PASSWORD_CHECK)
  @ApiOperation({ summary: 'Check if a password appears in any data breaches' })
  @ApiBody({ type: PasswordCheckDto })
  @ApiResponse({
    status: 200,
    description: 'Results of the password breach check',
    schema: {
      type: 'object',
      properties: {
        found: { type: 'boolean', example: true },
        count: { type: 'number', example: 103542 },
      },
    },
  })
  @ApiResponse({ status: 400, description: 'Bad request or invalid password' })
  @ApiResponse({ status: 429, description: 'Too many requests' })
  @RateLimit({
    message: 'Too many requests, please try again later',
    statusCode: HttpStatus.TOO_MANY_REQUESTS,
    headers: true,
    max: 20,
    windowMs: 60 * 1000,
  }) // 10 requests per minute
  async checkPassword(@Body(new ValidationPipe({ transform: true })) passwordDto: PasswordCheckDto) {
    try {
      // Don't log the actual password
      this.logger.log('Checking password :', passwordDto.password);
      return await this.breachCheckService.checkPassword(passwordDto.password);
    } catch (error) {
      if (error instanceof HttpException) {
        throw error;
      }
      this.logger.error(`Error in password check: ${error.message}`);
      throw new HttpException('Failed to check password', HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @Post('phone')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN, UserRole.CLIENT, UserRole.USER)
  // @Permissions(FeatureEnum.BC_PHONE_CHECK)
  @ApiOperation({ summary: 'Check if a phone number appears in any data breaches' })
  @ApiBody({ type: PhoneCheckDto })
  @ApiResponse({
    status: 200,
    description: 'Results of the phone breach check',
    schema: {
      type: 'object',
      properties: {
        found: { type: 'boolean', example: true },
        breaches: {
          type: 'array',
          items: {
            type: 'object',
            properties: {
              id: { type: 'number', example: 1 },
              source: { type: 'string', example: 'Company X Breach 2024' },
              date: { type: 'string', format: 'date-time', example: '2022-06-15T10:20:30.000Z' },
            },
          },
        },
      },
    },
  })
  @ApiResponse({ status: 400, description: 'Bad request or invalid phone number' })
  @ApiResponse({ status: 429, description: 'Too many requests' })
  @RateLimit({
    message: 'Too many requests, please try again later',
    statusCode: HttpStatus.TOO_MANY_REQUESTS,
    headers: true,
    max: 20,
    windowMs: 60 * 1000,
  }) // 20 requests per minute
  async checkPhone(@Body(new ValidationPipe({ transform: true })) phoneDto: PhoneCheckDto) {
    try {
      // this.logger.log(`Checking phone: ${this.maskPhone(phoneDto.phone)}`);
      return await this.breachCheckService.checkPhone(phoneDto.phone);
    } catch (error) {
      if (error instanceof HttpException) {
        throw error;
      }
      this.logger.error(`Error in phone check: ${error.message}`);
      throw new HttpException('Failed to check phone number', HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @Get('stats')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN, UserRole.CLIENT, UserRole.USER)
  // @Permissions(FeatureEnum.BC_STATS)
  @ApiOperation({ summary: 'Get statistics about the breach database' })
  @ApiResponse({
    status: 200,
    description: 'Statistics about the breach database',
    schema: {
      type: 'object',
      properties: {
        totalRecords: { type: 'number', example: 7532689 },
        uniqueEmails: { type: 'number', example: 3624571 },
        uniquePasswords: { type: 'number', example: 5421389 },
        sources: {
          type: 'array',
          items: {
            type: 'object',
            properties: {
              source: { type: 'string', example: 'Collection #1' },
              count: { type: 'number', example: 1240567 },
            },
          },
        },
      },
    },
  })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  async getBreachStats() {
    try {
      return await this.breachCheckService.getBreachStats();
    } catch (error) {
      this.logger.error(`Error retrieving breach statistics: ${error.message}`);
      throw new HttpException('Failed to retrieve breach statistics', HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @Get('status')
  @Roles(UserRole.SUPER_ADMIN, UserRole.ADMIN, UserRole.CLIENT, UserRole.USER)
  // @Permissions(FeatureEnum.BC_STATUS)
  @ApiOperation({ summary: 'Check if the breach check service is up and running' })
  @ApiResponse({ status: 200, description: 'Service is operational' })
  async getServiceStatus() {
    try {
      return {
        status: 'operational',
        timestamp: new Date().toISOString(),
        version: process.env.APP_VERSION || '1.0.0',
      };
    } catch (error) {
      this.logger.error(`Service status check failed: ${error.message}`);
      return {
        status: 'degraded',
        timestamp: new Date().toISOString(),
        message: 'Database connection issues',
      };
    }
  }

  /**
   * Masks email for logging purposes
   */
  private maskEmail(email: string): string {
    if (!email || email.length < 5) return '****';

    const parts = email.split('@');
    if (parts.length !== 2) return '****';

    const username = parts[0];
    const domain = parts[1];

    const maskedUsername = username.substring(0, 2) + '****';
    return `${maskedUsername}@${domain}`;
  }
}
