const mongoose = require('mongoose');

const blockedDeviceSchema = new mongoose.Schema(
  {
    deviceFingerprint: {
      type: String,
      required: true,
      index: true,
      unique: true
    },
    blockedBy: {
      type: mongoose.Schema.Types.ObjectId,
      ref: 'User',
      required: true
    },
    blockedUserId: {
      type: mongoose.Schema.Types.ObjectId,
      ref: 'User',
      required: true
    },
    reason: {
      type: String,
      required: true,
      maxlength: 500
    },
    blockedAt: {
      type: Date,
      default: Date.now
    },
    isActive: {
      type: Boolean,
      default: true
    },
    // Дополнительная информация об устройстве для анализа
    deviceInfo: {
      userAgent: String,
      screenResolution: String,
      platform: String,
      language: String,
      timezone: String,
      ipAddress: String, // Сохраняем IP для дополнительного анализа
      lastSeen: {
        type: Date,
        default: Date.now
      }
    },
    // Попытки обхода блокировки
    bypassAttempts: [{
      timestamp: {
        type: Date,
        default: Date.now
      },
      attemptType: {
        type: String,
        enum: ['login', 'register', 'api_request'],
        required: true
      },
      ipAddress: String,
      userAgent: String,
      blocked: {
        type: Boolean,
        default: true
      }
    }],
    // Связанные fingerprints (для обнаружения похожих устройств)
    relatedFingerprints: [{
      fingerprint: String,
      similarity: Number, // Процент схожести
      detectedAt: {
        type: Date,
        default: Date.now
      }
    }],
    unblockRequests: [{
      requestedAt: {
        type: Date,
        default: Date.now
      },
      requestedBy: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User'
      },
      reason: String,
      status: {
        type: String,
        enum: ['pending', 'approved', 'rejected'],
        default: 'pending'
      },
      reviewedBy: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User'
      },
      reviewedAt: Date,
      reviewNote: String
    }]
  },
  {
    timestamps: true,
  }
);

// Индексы для оптимизации поиска
blockedDeviceSchema.index({ deviceFingerprint: 1, isActive: 1 });
blockedDeviceSchema.index({ blockedUserId: 1 });
blockedDeviceSchema.index({ blockedAt: 1 });
blockedDeviceSchema.index({ 'deviceInfo.ipAddress': 1 });

// Методы модели
blockedDeviceSchema.methods.addBypassAttempt = function(attemptData) {
  this.bypassAttempts.push({
    attemptType: attemptData.type,
    ipAddress: attemptData.ipAddress,
    userAgent: attemptData.userAgent,
    blocked: true
  });
  
  // Ограничиваем количество записей попыток
  if (this.bypassAttempts.length > 100) {
    this.bypassAttempts = this.bypassAttempts.slice(-100);
  }
  
  return this.save();
};

blockedDeviceSchema.methods.addRelatedFingerprint = function(fingerprint, similarity) {
  // Проверяем, не добавлен ли уже этот fingerprint
  const exists = this.relatedFingerprints.find(rf => rf.fingerprint === fingerprint);
  if (!exists) {
    this.relatedFingerprints.push({
      fingerprint,
      similarity
    });
    
    // Ограничиваем количество связанных fingerprints
    if (this.relatedFingerprints.length > 50) {
      this.relatedFingerprints = this.relatedFingerprints.slice(-50);
    }
  }
  
  return this.save();
};

blockedDeviceSchema.methods.unblock = function(unblockedBy, reason) {
  this.isActive = false;
  this.unblockRequests.push({
    requestedBy: unblockedBy,
    reason: reason || 'Разблокировано администратором',
    status: 'approved',
    reviewedBy: unblockedBy,
    reviewedAt: new Date(),
    reviewNote: 'Разблокировано напрямую'
  });
  
  return this.save();
};

// Статические методы
blockedDeviceSchema.statics.isDeviceBlocked = async function(deviceFingerprint) {
  const blockedDevice = await this.findOne({
    deviceFingerprint,
    isActive: true
  }).populate('blockedUserId', 'name email');
  
  return blockedDevice;
};

blockedDeviceSchema.statics.blockDevice = async function(deviceData) {
  const {
    deviceFingerprint,
    blockedBy,
    blockedUserId,
    reason,
    deviceInfo
  } = deviceData;
  
  // Проверяем, не заблокировано ли уже устройство
  const existing = await this.findOne({ deviceFingerprint });
  
  if (existing) {
    if (!existing.isActive) {
      // Реактивируем блокировку
      existing.isActive = true;
      existing.reason = reason;
      existing.blockedBy = blockedBy;
      existing.blockedAt = new Date();
      if (deviceInfo) {
        existing.deviceInfo = { ...existing.deviceInfo, ...deviceInfo };
      }
      return await existing.save();
    } else {
      // Устройство уже заблокировано
      return existing;
    }
  }
  
  // Создаем новую блокировку
  const blockedDevice = new this({
    deviceFingerprint,
    blockedBy,
    blockedUserId,
    reason,
    deviceInfo
  });
  
  return await blockedDevice.save();
};

blockedDeviceSchema.statics.findSimilarDevices = async function(deviceFingerprint, threshold = 0.8) {
  // Простой алгоритм поиска похожих fingerprints
  const allDevices = await this.find({ isActive: true });
  const similar = [];
  
  for (const device of allDevices) {
    const similarity = this.calculateSimilarity(deviceFingerprint, device.deviceFingerprint);
    if (similarity >= threshold) {
      similar.push({
        device,
        similarity
      });
    }
  }
  
  return similar.sort((a, b) => b.similarity - a.similarity);
};

blockedDeviceSchema.statics.calculateSimilarity = function(fp1, fp2) {
  if (fp1 === fp2) return 1.0;
  
  // Простой алгоритм сравнения строк
  const longer = fp1.length > fp2.length ? fp1 : fp2;
  const shorter = fp1.length > fp2.length ? fp2 : fp1;
  
  if (longer.length === 0) return 1.0;
  
  const editDistance = this.levenshteinDistance(longer, shorter);
  return (longer.length - editDistance) / longer.length;
};

blockedDeviceSchema.statics.levenshteinDistance = function(str1, str2) {
  const matrix = [];
  
  for (let i = 0; i <= str2.length; i++) {
    matrix[i] = [i];
  }
  
  for (let j = 0; j <= str1.length; j++) {
    matrix[0][j] = j;
  }
  
  for (let i = 1; i <= str2.length; i++) {
    for (let j = 1; j <= str1.length; j++) {
      if (str2.charAt(i - 1) === str1.charAt(j - 1)) {
        matrix[i][j] = matrix[i - 1][j - 1];
      } else {
        matrix[i][j] = Math.min(
          matrix[i - 1][j - 1] + 1,
          matrix[i][j - 1] + 1,
          matrix[i - 1][j] + 1
        );
      }
    }
  }
  
  return matrix[str2.length][str1.length];
};

// Middleware для обновления lastSeen
blockedDeviceSchema.pre('save', function(next) {
  if (this.deviceInfo) {
    this.deviceInfo.lastSeen = new Date();
  }
  next();
});

module.exports = mongoose.model('BlockedDevice', blockedDeviceSchema);