import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { MoreThan, Between, In, Contains } from '../common/typeorm-operators';
import { Repository } from 'typeorm';
import { AuditLog } from '../entities/audit-log.entity';
import { ConfigService } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class SecurityService {
  constructor(
    @InjectRepository(AuditLog)
    private readonly auditLogRepository: Repository<AuditLog>,
    private configService: ConfigService,
    private jwtService: JwtService,
  ) {}

  async logActivity(
    userId: string,
    action: string,
    resource: string,
    details: any,
    ipAddress: string,
  ): Promise<void> {
    const log = this.auditLogRepository.create({
      user: { id: userId },
      action,
      details,
      resource,
      ipAddress,
      timestamp: new Date(),
    });

    await this.auditLogRepository.save(log);
  }

  async getAuditLogs(
    userId?: string,
    resource?: string,
    startDate?: Date,
    endDate?: Date,
    limit = 100,
  ): Promise<AuditLog[]> {
    const query = this.auditLogRepository.createQueryBuilder('log');

    if (userId) {
      query.andWhere('log.userId = :userId', { userId });
    }

    if (resource) {
      query.andWhere('log.resource = :resource', { resource });
    }

    if (startDate) {
      query.andWhere('log.timestamp >= :startDate', { startDate });
    }

    if (endDate) {
      query.andWhere('log.timestamp <= :endDate', { endDate });
    }

    query.orderBy('log.timestamp', 'DESC').limit(limit);

    return query.getMany();
  }

  async getSecurityMetrics(): Promise<any> {
    const [totalLogs, failedAuthAttempts, suspiciousActivities] = await Promise.all([
      this.auditLogRepository.count(),
      this.auditLogRepository.count({
        where: { action: 'failed_auth' },
      }),
      this.auditLogRepository.count({
        where: {
          action: In(['failed_auth', 'unauthorized_access', 'permission_denied']),
        },
      }),
    ]);

    return {
      totalLogs,
      failedAuthAttempts,
      suspiciousActivities,
      last24Hours: await this.getAuditLogs(
        undefined,
        undefined,
        new Date(Date.now() - 24 * 60 * 60 * 1000),
      ),
    };
  }

  async validateInput(data: any): Promise<void> {
    // Basic SQL injection prevention
    if (typeof data === 'string') {
      if (/(ALTER|CREATE|DELETE|DROP|EXEC|INSERT|SELECT|UPDATE|UNION)\b/i.test(data)) {
        throw new Error('Invalid input: potential SQL injection attempt');
      }
    }

    // XSS prevention
    if (typeof data === 'string') {
      if (/(script|on[a-z]+|javascript:|data:|alert\()\b/i.test(data)) {
        throw new Error('Invalid input: potential XSS attempt');
      }
    }

    // Rate limiting
    const recentAttempts = await this.auditLogRepository.find({
      where: {
        action: 'auth_attempt',
        timestamp: MoreThan(new Date(Date.now() - 5 * 60 * 1000)), // Last 5 minutes
      },
    });

    if (recentAttempts.length > this.configService.get('RATE_LIMIT_ATTEMPTS')) {
      throw new Error('Too many attempts. Please try again later.');
    }
  }

  async checkTokenValidity(token: string): Promise<boolean> {
    try {
      // Verify JWT token
      const decoded = await this.verifyToken(token);
      
      // Check if token has been revoked
      const revoked = await this.auditLogRepository.findOne({
        where: {
          action: 'token_revoked',
          details: Contains(token),
        },
      });

      return !revoked;
    } catch (error) {
      return false;
    }
  }

  async verifyToken(token: string): Promise<any> {
    try {
      // Verify JWT token
      const decoded = await this.jwtService.verify(token);
      
      // Log successful token verification
      await this.logActivity(decoded.userId, 'token_verification', 'security', { token }, 'security');

      return decoded;
    } catch (error) {
      // Log failed token verification
      await this.logActivity(
        error.userId || 'unknown',
        'token_verification',
        'security',
        { success: false, error: error.message },
        'security',
      );

      throw error;
    }
  }
}
