/**
 * Система аудита доступа к коммерческим данным
 *
 * Логирует все обращения к чувствительной коммерческой информации,
 * отслеживает подозрительную активность и генерирует алерты
 */

import { PrismaClient } from '@prisma/client'

import { SecurityLogger } from '../../lib/security-logger'

import { CommercialAccessType, ResourceType, SecurityAlert, AuditParams, AlertThresholds } from './types'

/**
 * Статистика активности пользователя
 */
interface UserActivityStats {
  userId: string
  organizationType: string
  action: CommercialAccessType
  count: number
  timeframe: string
  lastAccess: Date
}

export class CommercialDataAudit {
  /**
   * Пороговые значения для различных типов доступа
   */
  private static readonly ALERT_THRESHOLDS: AlertThresholds = {
    VIEW_PRICE: {
      perHour: 100, // Максимум 100 просмотров цен в час
      perDay: 500, // Максимум 500 просмотров цен в день
    },
    VIEW_RECIPE: {
      perHour: 50, // Максимум 50 просмотров рецептур в час
      perDay: 200, // Максимум 200 просмотров рецептур в день
    },
    VIEW_CONTACTS: {
      perHour: 30, // Максимум 30 просмотров контактов в час
      perDay: 100, // Максимум 100 просмотров контактов в день
    },
    VIEW_MARGINS: {
      perHour: 20, // Максимум 20 просмотров маржинальности в час
      perDay: 80, // Максимум 80 просмотров маржинальности в день
    },
    BULK_EXPORT: {
      perHour: 5, // Максимум 5 экспортов в час
      perDay: 20, // Максимум 20 экспортов в день
    },
  }

  /**
   * Логирует доступ к коммерческим данным
   */
  static async logAccess(prisma: PrismaClient, params: AuditParams): Promise<void> {
    try {
      // Создаем запись в журнале аудита
      await prisma.auditLog.create({
        data: {
          userId: params.userId,
          organizationType: params.organizationType,
          action: `DATA_ACCESS:${params.action}`,
          resourceType: params.resourceType,
          resourceId: params.resourceId || null,
          metadata: params.metadata || {},
          ipAddress: params.ipAddress,
          userAgent: params.userAgent,
        },
      })

      // Логируем через SecurityLogger
      SecurityLogger.logDataAccess({
        userId: params.userId,
        organizationType: params.organizationType,
        action: params.action,
        resource: params.resourceType,
        resourceId: params.resourceId,
        filtered: false,
        ipAddress: params.ipAddress,
        userAgent: params.userAgent,
      })

      // Проверяем на подозрительную активность
      await this.checkSuspiciousActivity(prisma, params)
    } catch (error) {
      SecurityLogger.logSecurityError(error as Error, {
        operation: 'logAccess',
        params,
      })
    }
  }

  /**
   * Логирует попытку несанкционированного доступа
   */
  static async logUnauthorizedAccess(
    prisma: PrismaClient,
    params: {
      userId: string
      organizationType: string
      resourceType: ResourceType
      resourceId: string
      reason: string
      ipAddress?: string
      userAgent?: string
    },
  ): Promise<void> {
    try {
      // Записываем в журнал аудита
      await prisma.auditLog.create({
        data: {
          userId: params.userId,
          organizationType: params.organizationType,
          action: 'UNAUTHORIZED_ACCESS_ATTEMPT',
          resourceType: params.resourceType,
          resourceId: params.resourceId,
          metadata: {
            reason: params.reason,
            blocked: true,
          },
          ipAddress: params.ipAddress,
          userAgent: params.userAgent,
        },
      })

      // Генерируем алерт безопасности
      const alert: SecurityAlert = {
        id: `alert-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
        type: 'UNAUTHORIZED_ATTEMPT',
        severity: 'HIGH',
        userId: params.userId,
        message: `Unauthorized access attempt to ${params.resourceType} ${params.resourceId}`,
        metadata: {
          resourceType: params.resourceType,
          resourceId: params.resourceId,
          reason: params.reason,
          organizationType: params.organizationType,
          ipAddress: params.ipAddress,
          userAgent: params.userAgent,
        },
        timestamp: new Date(),
        resolved: false,
      }

      await this.processSecurityAlert(prisma, alert)

      SecurityLogger.logAccessAttempt({
        userId: params.userId,
        organizationType: params.organizationType,
        resource: params.resourceType,
        resourceId: params.resourceId,
        success: false,
        reason: params.reason,
        ipAddress: params.ipAddress,
        userAgent: params.userAgent,
      })
    } catch (error) {
      SecurityLogger.logSecurityError(error as Error, {
        operation: 'logUnauthorizedAccess',
        params,
      })
    }
  }

  /**
   * Проверяет подозрительную активность пользователя
   */
  private static async checkSuspiciousActivity(prisma: PrismaClient, params: AuditParams): Promise<void> {
    const threshold = this.ALERT_THRESHOLDS[params.action]
    if (!threshold) return

    try {
      // Считаем активность за последний час
      const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000)
      const hourlyCount = await this.getActivityCount(prisma, params.userId, params.action, oneHourAgo)

      // Проверяем превышение почасового лимита
      if (hourlyCount > threshold.perHour) {
        await this.sendExcessiveAccessAlert(prisma, {
          userId: params.userId,
          organizationType: params.organizationType,
          action: params.action,
          count: hourlyCount,
          threshold: threshold.perHour,
          timeframe: '1 hour',
          severity: 'HIGH',
        })
      }

      // Считаем активность за последние 24 часа
      const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000)
      const dailyCount = await this.getActivityCount(prisma, params.userId, params.action, oneDayAgo)

      // Проверяем превышение дневного лимита
      if (dailyCount > threshold.perDay) {
        await this.sendExcessiveAccessAlert(prisma, {
          userId: params.userId,
          organizationType: params.organizationType,
          action: params.action,
          count: dailyCount,
          threshold: threshold.perDay,
          timeframe: '24 hours',
          severity: 'MEDIUM',
        })
      }
    } catch (error) {
      SecurityLogger.logSecurityError(error as Error, {
        operation: 'checkSuspiciousActivity',
        userId: params.userId,
        action: params.action,
      })
    }
  }

  /**
   * Получает количество действий пользователя за период
   */
  private static async getActivityCount(
    prisma: PrismaClient,
    userId: string,
    action: CommercialAccessType,
    since: Date,
  ): Promise<number> {
    return await prisma.auditLog.count({
      where: {
        userId,
        action: { contains: action },
        timestamp: { gte: since },
      },
    })
  }

  /**
   * Отправляет алерт о чрезмерной активности
   */
  private static async sendExcessiveAccessAlert(
    prisma: PrismaClient,
    params: {
      userId: string
      organizationType: string
      action: CommercialAccessType
      count: number
      threshold: number
      timeframe: string
      severity: 'MEDIUM' | 'HIGH'
    },
  ): Promise<void> {
    const alert: SecurityAlert = {
      id: `alert-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
      type: 'EXCESSIVE_ACCESS',
      severity: params.severity,
      userId: params.userId,
      message:
        `Excessive ${params.action} activity: ${params.count} actions in ` +
        `${params.timeframe} (threshold: ${params.threshold})`,
      metadata: {
        action: params.action,
        count: params.count,
        threshold: params.threshold,
        timeframe: params.timeframe,
        organizationType: params.organizationType,
      },
      timestamp: new Date(),
      resolved: false,
    }

    await this.processSecurityAlert(prisma, alert)

    SecurityLogger.logSuspiciousActivity({
      userId: params.userId,
      organizationType: params.organizationType,
      activity: params.action,
      count: params.count,
      timeframe: params.timeframe,
      threshold: params.threshold,
    })
  }

  /**
   * Обрабатывает алерт безопасности
   */
  private static async processSecurityAlert(prisma: PrismaClient, alert: SecurityAlert): Promise<void> {
    try {
      // Сохраняем алерт в базу данных
      await prisma.securityAlert.create({
        data: {
          id: alert.id,
          type: alert.type,
          severity: alert.severity,
          userId: alert.userId,
          message: alert.message,
          metadata: alert.metadata,
          timestamp: alert.timestamp,
          resolved: alert.resolved,
        },
      })

      // Логируем алерт
      SecurityLogger.logSecurityAlert(alert)

      // Для критичных алертов - немедленная отправка уведомлений
      if (alert.severity === 'HIGH' || alert.severity === 'CRITICAL') {
        await this.sendImmediateNotification(alert)
      }
    } catch (error) {
      SecurityLogger.logSecurityError(error as Error, {
        operation: 'processSecurityAlert',
        alertId: alert.id,
      })
    }
  }

  /**
   * Отправляет немедленное уведомление о критичном алерте
   */
  private static async sendImmediateNotification(alert: SecurityAlert): Promise<void> {
    // TODO: Реализовать отправку уведомлений
    // - Email администраторам
    // - SMS для критичных алертов
    // - Slack/Teams уведомления
    // - Push уведомления в мобильное приложение

    console.error(`🚨 CRITICAL SECURITY ALERT: ${alert.message}`, {
      alertId: alert.id,
      userId: alert.userId,
      type: alert.type,
      severity: alert.severity,
      timestamp: alert.timestamp,
    })
  }

  /**
   * Получает статистику активности для пользователя
   */
  static async getUserActivityStats(
    prisma: PrismaClient,
    userId: string,
    period: '1h' | '24h' | '7d' = '24h',
  ): Promise<UserActivityStats[]> {
    const periodMs = {
      '1h': 60 * 60 * 1000,
      '24h': 24 * 60 * 60 * 1000,
      '7d': 7 * 24 * 60 * 60 * 1000,
    }

    const since = new Date(Date.now() - periodMs[period])

    try {
      const rawStats = await prisma.auditLog.groupBy({
        by: ['userId', 'organizationType', 'action'],
        where: {
          userId,
          timestamp: { gte: since },
          action: { startsWith: 'DATA_ACCESS:' },
        },
        _count: {
          action: true,
        },
        _max: {
          timestamp: true,
        },
      })

      return rawStats.map((stat) => ({
        userId: stat.userId,
        organizationType: (stat.organizationType as string) || 'UNKNOWN',
        action: stat.action.replace('DATA_ACCESS:', '') as CommercialAccessType,
        count: stat._count.action,
        timeframe: period,
        lastAccess: stat._max.timestamp || new Date(),
      }))
    } catch (error) {
      SecurityLogger.logSecurityError(error as Error, {
        operation: 'getUserActivityStats',
        userId,
        period,
      })
      return []
    }
  }

  /**
   * Получает активные алерты безопасности
   */
  static async getActiveAlerts(prisma: PrismaClient, limit: number = 50): Promise<SecurityAlert[]> {
    try {
      const alerts = await prisma.securityAlert.findMany({
        where: {
          resolved: false,
        },
        orderBy: {
          timestamp: 'desc',
        },
        take: limit,
      })

      return alerts.map((alert) => ({
        id: alert.id,
        type: alert.type as SecurityAlert['type'],
        severity: alert.severity as SecurityAlert['severity'],
        userId: alert.userId,
        message: alert.message,
        metadata: alert.metadata as Record<string, unknown>,
        timestamp: alert.timestamp,
        resolved: alert.resolved,
      }))
    } catch (error) {
      SecurityLogger.logSecurityError(error as Error, {
        operation: 'getActiveAlerts',
      })
      return []
    }
  }

  /**
   * Помечает алерт как разрешенный
   */
  static async resolveAlert(prisma: PrismaClient, alertId: string, resolvedBy: string): Promise<void> {
    try {
      await prisma.securityAlert.update({
        where: { id: alertId },
        data: {
          resolved: true,
          metadata: {
            resolvedBy,
            resolvedAt: new Date(),
          },
        },
      })
    } catch (error) {
      SecurityLogger.logSecurityError(error as Error, {
        operation: 'resolveAlert',
        alertId,
        resolvedBy,
      })
    }
  }
}
