/**
 * Card Generator Tool - 卡片生成工具
 * 100%保持旧框架逻辑不变
 */

import { BaseTool } from '../ITool';
import { randomInt, randomDigits, padZero, generateLuhnNumber } from './utils';
import { CARD_TYPES, EXPIRY_CONFIG, CardTypeConfig, BinInfo } from './config';
import { DatabaseTool } from '../DatabaseTool';

export interface CardInfo {
  number: string;
  month: string;
  year: string;
  cvv: string;
  type: string;
  issuer: string;
  country: string;
  countryName: string;
}

export interface CardGeneratorConfig {
  type?: string;
  database?: DatabaseTool;
}

export class CardGeneratorTool extends BaseTool<CardGeneratorConfig> {
  readonly name = 'card-generator';
  
  private cardTypes = CARD_TYPES;
  private expiryConfig = EXPIRY_CONFIG;
  private usedNumbers = new Set<string>();
  private database: DatabaseTool | null = null;
  private lastBinInfo: any = null;
  
  protected validateConfig(config: CardGeneratorConfig): void {
    // 配置是可选的
  }
  
  protected async doInitialize(): Promise<void> {
    this.database = this.config.database || null;
  }

  /**
   * 生成卡号（带去重机制 + 数据库查重）
   * @param {string} type - 卡类型
   * @returns {Promise<string>}
   */
  async generateCardNumber(type: string): Promise<string> {
    const config = this.cardTypes[type];
    if (!config) {
      throw new Error(`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 Error(`无法生成唯一卡号（${maxAttempts}次尝试后仍重复）`);
  }
  
  /**
   * 检查卡号是否在数据库中已存在
   * @param {string} cardNumber - 卡号
   * @returns {Promise<boolean>}
   */
  private async checkCardNumberInDatabase(cardNumber: string): Promise<boolean> {
    try {
      // 检查数据库连接是否已初始化
      if (!this.database) {
        return false; // 数据库未初始化，跳过数据库查询
      }
      
      const rows = await this.database.find('windsurf_accounts', { payment_card_number: cardNumber });
      return rows.length > 0;
    } catch (error) {
      // 如果数据库查询失败，静默降级（不输出，避免乱码）
      return false;
    }
  }
  
  /**
   * 内部生成逻辑（不含去重）
   * @param {string} type - 卡类型
   * @param {Object} config - 卡类型配置
   * @returns {string}
   */
  private _generateCardNumberInternal(type: string, config: CardTypeConfig): string {
    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 Error(`卡类型 ${type} 未配置有效的前缀`);
    }

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

    const digitsNeeded = length - selectedPrefix.length - 1;
    if (digitsNeeded <= 0) {
      throw new Error(`前缀配置错误：无法为 ${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.5) {
        // 50% 马尔可夫链生成（考虑位置关联性）
        return this.generateByWeights(selectedPrefix, digitsNeeded, length);
      }
      if (rand < 0.9) {
        // 40% 变异生成（从成功案例变异1-2位）
        return this.generateByMutation(selectedPrefix, successfulPatterns || [], generation?.mutationDigits || [1, 1], digitsNeeded, length);
      }
      // 10% 纯随机（保持多样性）
    }

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

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

  private selectPrefix(defaultPrefix?: string, prefixes?: BinInfo[]): any {
    const options: any[] = [];

    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) > 0 ? (item.weight || 1) : 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: number, item: any) => 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}
   */
  private generateByMutation(prefix: string, patterns: string[], mutationDigits: [number, number], digitsNeeded: number, totalLength: number): string {
    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;
  }

  /**
   * 基于马尔可夫链生成卡号（考虑位置之间的关联性）
   * @param {string} prefix - BIN前缀
   * @param {number} digitsNeeded - 需要生成的主体位数（不含校验位）
   * @param {number} totalLength - 卡号总长度
   * @returns {string}
   */
  private generateByWeights(prefix: string, digitsNeeded: number, totalLength: number): string {
    if (digitsNeeded <= 0) {
      return generateLuhnNumber(prefix, totalLength);
    }

    if (digitsNeeded !== 2) {
      // 如果不是2位，降级到纯随机
      return generateLuhnNumber(prefix, totalLength);
    }

    // 第1位：百位的权重分布
    const firstDigitWeights = [12, 7, 10, 7, 8, 5, 5, 9, 6, 1];
    const firstDigit = this.weightedRandomDigit(firstDigitWeights);
    
    // 第2位：基于第1位的马尔可夫转移概率
    const markovTransitions: Record<string, number[]> = {
      '0': [3, 1, 1, 2, 0, 2, 1, 2, 0, 0],
      '1': [0, 0, 2, 0, 1, 2, 0, 2, 0, 0],
      '2': [2, 0, 0, 0, 1, 2, 0, 1, 4, 0],
      '3': [0, 2, 2, 0, 0, 0, 1, 2, 0, 0],
      '4': [1, 0, 1, 0, 3, 0, 0, 1, 1, 1],
      '5': [0, 3, 1, 0, 0, 0, 0, 0, 1, 0],
      '6': [1, 0, 0, 0, 1, 0, 0, 1, 1, 1],
      '7': [1, 1, 1, 1, 0, 0, 1, 0, 2, 2],
      '8': [1, 0, 0, 0, 0, 1, 0, 1, 0, 3],
      '9': [0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
    };
    
    const secondDigitWeights = markovTransitions[firstDigit] || [1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
    const secondDigit = this.weightedRandomDigit(secondDigitWeights);
    
    const pattern = firstDigit + secondDigit;
    const partial = prefix + pattern;
    const checkDigit = this.calculateLuhnCheckDigit(partial);

    return partial + checkDigit;
  }
  
  /**
   * 按权重随机选择数字
   * @param {Array} weights - 权重数组（10个元素，对应数字0-9）
   * @returns {string}
   */
  private weightedRandomDigit(weights: number[]): string {
    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}
   */
  private calculateLuhnCheckDigit(partial: string): string {
    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}}
   */
  private generateExpiry(): { month: string; year: string } {
    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}
   */
  private generateCVV(type: string): string {
    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);
  }


  /**
   * 生成完整的信用卡信息（主要API）
   */
  async generate(type: string = 'unionpay'): Promise<CardInfo> {
    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,
      countryName
    };
  }
  
  /**
   * 批量生成
   */
  async generateBatch(count: number, type: string = 'unionpay'): Promise<CardInfo[]> {
    const cards: CardInfo[] = [];
    for (let i = 0; i < count; i++) {
      cards.push(await this.generate(type));
    }
    return cards;
  }

  /**
   * 获取所有支持的卡类型
   */
  getSupportedTypes() {
    return Object.keys(this.cardTypes).map(key => ({
      id: key,
      name: this.cardTypes[key].name
    }));
  }
  
  async cleanup(): Promise<void> {
    console.log('  ✓ card-generator cleaned up');
  }
}

// 导出已在类定义中完成
