/**
 * Card Generator - 核心生成逻辑
 */

const { randomInt, randomDigits, padZero, generateLuhnNumber } = require('../../utils');
const { CARD_TYPES, EXPIRY_CONFIG } = require('./config');
const { ValidationError } = require('../../errors');

class CardGenerator {
  constructor(database = null) {
    this.cardTypes = CARD_TYPES;
    this.expiryConfig = EXPIRY_CONFIG;
    this.usedNumbers = new Set();  // 去重机制：记录已生成的卡号
    this.database = database;      // 数据库连接（可选）
    this.lastBinInfo = null;       // 最后使用的BIN信息
  }

  /**
   * 生成卡号（带去重机制 + 数据库查重）
   * @param {string} type - 卡类型
   * @returns {Promise<string>}
   */
  async generateCardNumber(type) {
    const config = this.cardTypes[type];
    if (!config) {
      throw new ValidationError('card-generator', `Unknown card type: ${type}`);
    }

    // 尝试生成唯一卡号（最多100次）
    let attempts = 0;
    const maxAttempts = 100;
    
    while (attempts < maxAttempts) {
      const cardNumber = this._generateCardNumberInternal(type, config);
      
      // 检查1：内存去重（本次运行）
      if (this.usedNumbers.has(cardNumber)) {
        attempts++;
        continue;
      }
      
      // 检查2：数据库去重（历史记录）
      if (this.database) {
        const existsInDb = await this.checkCardNumberInDatabase(cardNumber);
        if (existsInDb) {
          attempts++;
          continue;
        }
      }
      
      // 通过所有检查，记录并返回
      this.usedNumbers.add(cardNumber);
      return cardNumber;
    }
    
    throw new ValidationError('card-generator', `无法生成唯一卡号（${maxAttempts}次尝试后仍重复）`);
  }
  
  /**
   * 检查卡号是否在数据库中已存在
   * @param {string} cardNumber - 卡号
   * @returns {Promise<boolean>}
   */
  async checkCardNumberInDatabase(cardNumber) {
    try {
      // 检查数据库连接是否已初始化
      if (!this.database || !this.database.pool) {
        return false; // 数据库未初始化，跳过数据库查询
      }
      
      const sql = 'SELECT COUNT(*) as count FROM windsurf_accounts WHERE payment_card_number = ?';
      const rows = await this.database.query(sql, [cardNumber]);
      return rows[0].count > 0;
    } catch (error) {
      // 如果数据库查询失败，静默降级（不输出，避免乱码）
      return false;
    }
  }
  
  /**
   * 内部生成逻辑（不含去重）
   * @param {string} type - 卡类型
   * @param {Object} config - 卡类型配置
   * @returns {string}
   */
  _generateCardNumberInternal(type, config) {
    const { prefix, prefixes, length, useLuhn, successfulPatterns, generation } = config;

    const prefixInfo = this.selectPrefix(prefix, prefixes);
    this.lastBinInfo = prefixInfo;  // 保存BIN信息
    const selectedPrefix = prefixInfo.fullPrefix;

    if (!selectedPrefix) {
      throw new ValidationError('card-generator', `卡类型 ${type} 未配置有效的前缀`);
    }

    if (selectedPrefix.length >= length) {
      throw new ValidationError('card-generator', `前缀长度(${selectedPrefix.length}) 不得大于或等于卡号总长度(${length})`);
    }

    const digitsNeeded = length - selectedPrefix.length - 1;
    if (digitsNeeded <= 0) {
      throw new ValidationError('card-generator', `前缀配置错误：无法为 ${type} 生成剩余位数`);
    }

    const patternLength = successfulPatterns && successfulPatterns.length > 0
      ? successfulPatterns[0].length
      : null;
    const canUseAdvancedStrategies = Boolean(
      generation &&
      successfulPatterns &&
      successfulPatterns.length > 0 &&
      prefixInfo.supportsPatterns &&
      patternLength === digitsNeeded + 1
    );

    if (canUseAdvancedStrategies) {
      const rand = Math.random();

      if (rand < 0.2) {
        return this.generateByWeights(selectedPrefix, digitsNeeded, length);
      }
      if (rand < 0.8) {
        return this.generateByMutation(selectedPrefix, successfulPatterns, generation.mutationDigits, digitsNeeded, length);
      }
      // 其余概率走纯随机策略
    }

    if (useLuhn) {
      return generateLuhnNumber(selectedPrefix, length);
    }

    const remainingLength = length - selectedPrefix.length;
    return selectedPrefix + randomDigits(remainingLength);
  }

  selectPrefix(defaultPrefix, prefixes) {
    const options = [];

    if (Array.isArray(prefixes) && prefixes.length > 0) {
      prefixes.forEach((item) => {
        if (!item) return;

        if (typeof item === 'string') {
          options.push({
            fullPrefix: item,
            weight: 1,
            supportsPatterns: true
          });
          return;
        }

        if (typeof item === 'object') {
          const bin = typeof item.bin === 'string' ? item.bin : '';
          const extension = typeof item.extension === 'string' ? item.extension : '';
          const fullPrefix = typeof item.fullPrefix === 'string' ? item.fullPrefix : `${bin}${extension}`;

          if (!fullPrefix) {
            return;
          }

          const weight = Number.isFinite(item.weight) && item.weight > 0 ? item.weight : 1;
          const supportsPatterns = item.allowPatterns !== false;
          const issuer = item.issuer || '未知';
          const country = item.country || 'CN';

          options.push({ fullPrefix, weight, supportsPatterns, issuer, country });
        }
      });
    }

    if (options.length === 0 && defaultPrefix) {
      return { fullPrefix: defaultPrefix, supportsPatterns: true };
    }

    if (options.length === 0) {
      return { fullPrefix: null, supportsPatterns: false };
    }

    const totalWeight = options.reduce((sum, item) => sum + item.weight, 0);
    let randomValue = Math.random() * totalWeight;

    for (const option of options) {
      randomValue -= option.weight;
      if (randomValue <= 0) {
        return option;
      }
    }

    return options[options.length - 1];
  }
  
  /**
   * 基于真实案例变异生成卡号
   * @param {string} prefix - BIN前缀
   * @param {Array<string>} patterns - 成功案例的后缀（含校验位）
   * @param {Array<number>} mutationDigits - 变异数字个数[min, max]
   * @param {number} digitsNeeded - 需要生成的主体位数（不含校验位）
   * @param {number} totalLength - 卡号总长度
   * @returns {string}
   */
  generateByMutation(prefix, patterns, mutationDigits, digitsNeeded, totalLength) {
    if (!Array.isArray(patterns) || patterns.length === 0) {
      return generateLuhnNumber(prefix, totalLength);
    }

    const basePattern = patterns[randomInt(0, patterns.length - 1)];
    if (typeof basePattern !== 'string' || basePattern.length !== digitsNeeded + 1) {
      return generateLuhnNumber(prefix, totalLength);
    }

    const bodyDigits = basePattern.slice(0, digitsNeeded).split('');

    let minChanges = 1;
    let maxChanges = 1;
    if (Array.isArray(mutationDigits) && mutationDigits.length > 0) {
      const [minRaw, maxRaw] = mutationDigits;
      if (Number.isFinite(minRaw)) {
        minChanges = Math.max(0, minRaw);
      }
      if (Number.isFinite(maxRaw)) {
        maxChanges = Math.max(minChanges, maxRaw);
      } else {
        maxChanges = Math.max(minChanges, minChanges);
      }
    }

    maxChanges = Math.min(maxChanges, digitsNeeded);
    minChanges = Math.min(minChanges, maxChanges);
    const changeCount = maxChanges > 0 ? randomInt(minChanges, maxChanges) : 0;

    const changedPositions = new Set();
    for (let i = 0; i < changeCount; i++) {
      let pos;
      do {
        pos = randomInt(0, bodyDigits.length - 1);
      } while (changedPositions.has(pos));

      changedPositions.add(pos);

      let newDigit;
      do {
        newDigit = randomInt(0, 9).toString();
      } while (newDigit === bodyDigits[pos]);

      bodyDigits[pos] = newDigit;
    }

    const partial = prefix + bodyDigits.join('');
    const checkDigit = this.calculateLuhnCheckDigit(partial);

    return partial + checkDigit;
  }

  /**
   * 基于统计权重生成卡号（60个成功案例的分布）
   * @param {string} prefix - BIN前缀
   * @param {number} digitsNeeded - 需要生成的主体位数（不含校验位）
   * @param {number} totalLength - 卡号总长度
   * @returns {string}
   */
  generateByWeights(prefix, digitsNeeded, totalLength) {
    if (digitsNeeded <= 0) {
      return generateLuhnNumber(prefix, totalLength);
    }

    // 基于60个成功案例的位置权重（频率分布）
    const positionWeights = [
      [7, 5, 8, 2, 5, 7, 6, 7, 6, 7], // 位置1
      [7, 5, 7, 4, 11, 4, 2, 8, 8, 4], // 位置2
      [5, 4, 4, 9, 6, 7, 7, 6, 5, 7], // 位置3
      [12, 5, 8, 7, 7, 5, 4, 6, 5, 1], // 位置4: 数字0占20%
      [9, 6, 7, 3, 5, 6, 3, 9, 7, 5], // 位置5
      [10, 4, 5, 9, 7, 8, 4, 5, 6, 2], // 位置6
      [7, 3, 7, 2, 9, 6, 4, 6, 9, 7], // 位置7
    ];
    
    if (digitsNeeded > positionWeights.length) {
      return generateLuhnNumber(prefix, totalLength);
    }

    let pattern = '';
    for (let pos = 0; pos < digitsNeeded; pos++) {
      const weights = positionWeights[pos];
      const digit = this.weightedRandomDigit(weights);
      pattern += digit;
    }

    const partial = prefix + pattern;
    const checkDigit = this.calculateLuhnCheckDigit(partial);

    return partial + checkDigit;
  }
  
  /**
   * 按权重随机选择数字
   * @param {Array} weights - 权重数组（10个元素，对应数字0-9）
   * @returns {string}
   */
  weightedRandomDigit(weights) {
    const total = weights.reduce((sum, w) => sum + w, 0);
    let random = Math.random() * total;
    
    for (let i = 0; i < weights.length; i++) {
      random -= weights[i];
      if (random <= 0) return i.toString();
    }
    
    return randomInt(0, 9).toString();
  }
  
  /**
   * 计算Luhn校验位
   * @param {string} partial - 不含校验位的卡号
   * @returns {string}
   */
  calculateLuhnCheckDigit(partial) {
    let sum = 0;
    let isEven = true;
    
    for (let i = partial.length - 1; i >= 0; i--) {
      let digit = parseInt(partial[i]);
      
      if (isEven) {
        digit *= 2;
        if (digit > 9) digit -= 9;
      }
      
      sum += digit;
      isEven = !isEven;
    }
    
    return ((10 - (sum % 10)) % 10).toString();
  }

  /**
   * 生成有效期
   * @returns {{month: string, year: string}}
   */
  generateExpiry() {
    const month = randomInt(this.expiryConfig.minMonth, this.expiryConfig.maxMonth);
    const year = randomInt(this.expiryConfig.minYear, this.expiryConfig.maxYear);

    return {
      month: padZero(month, 2),
      year: padZero(year, 2)
    };
  }

  /**
   * 生成CVV安全码
   * @param {string} type - 卡类型
   * @returns {string}
   */
  generateCVV(type) {
    const config = this.cardTypes[type];
    const cvvLength = config.cvvLength;
    const maxValue = Math.pow(10, cvvLength) - 1;
    const cvv = randomInt(0, maxValue);
    return padZero(cvv, cvvLength);
  }

  /**
   * 生成完整的信用卡信息
   * @param {string} type - 卡类型，默认'unionpay'
   * @returns {Promise<Object>}
   */
  async generate(type = 'unionpay') {
    const number = await this.generateCardNumber(type);
    const expiry = this.generateExpiry();
    const cvv = this.generateCVV(type);

    // 获取银行和国家信息
    const issuer = this.lastBinInfo?.issuer || '未知';
    const country = this.lastBinInfo?.country || 'CN';
    const countryName = country === 'MO' ? '澳门' : '中国';

    return {
      number,
      month: expiry.month,
      year: expiry.year,
      cvv,
      type: this.cardTypes[type].name,
      issuer,        // 发卡银行
      country,       // 国家代码 (CN/MO)
      countryName    // 国家名称
    };
  }

  /**
   * 批量生成
   * @param {number} count - 数量
   * @param {string} type - 卡类型
   * @returns {Promise<Array>}
   */
  async generateBatch(count, type = 'unionpay') {
    const cards = [];
    for (let i = 0; i < count; i++) {
      cards.push(await this.generate(type));
    }
    return cards;
  }

  /**
   * 获取所有支持的卡类型
   * @returns {Array}
   */
  getSupportedTypes() {
    return Object.keys(this.cardTypes).map(key => ({
      id: key,
      name: this.cardTypes[key].name
    }));
  }
}

module.exports = CardGenerator;
