import { Injectable, Logger } from "@nestjs/common";

export interface TotoMatchSelectionInput {
  matchOrder: number;
  selections: ("1" | "X" | "2")[];
}

export interface GeneratedColumn {
  predictions: string; // "1X2102X112X2101" — 15 chars
}

/**
 * Kombinatorik kolon üretim motoru.
 * Tam Sistem (Full System): Tüm olası kombinasyonları üretir (2^d × 3^t).
 * İndirgenmiş Sistem (Reduced): Belirli bir kapak garantisi ile kolon sayısını azaltır.
 */
@Injectable()
export class TotoCombinatoricsService {
  private readonly logger = new Logger(TotoCombinatoricsService.name);

  /**
   * Tam Sistemli Kolon Üretimi
   * Her maç için seçilen tahminlerin tüm olası kombinasyonlarını üretir.
   *
   * @param matchSelections 15 maç için seçimler
   * @returns Tüm olası kolonlar
   */
  generateFullSystem(
    matchSelections: TotoMatchSelectionInput[],
  ): GeneratedColumn[] {
    // 15 maçlık tam liste oluştur (seçim yapılmayan maçlara default '1' ata)
    const selectionsMap = new Map<number, string[]>();
    matchSelections.forEach((ms) => {
      selectionsMap.set(ms.matchOrder, ms.selections);
    });

    const orderedSelections: string[][] = [];
    for (let i = 1; i <= 15; i++) {
      const sel = selectionsMap.get(i);
      if (!sel || sel.length === 0) {
        orderedSelections.push(["1"]); // Default: ev sahibi
      } else {
        orderedSelections.push(sel);
      }
    }

    // Toplam kolon sayısını hesapla
    const totalColumns = orderedSelections.reduce(
      (acc, sel) => acc * sel.length,
      1,
    );

    this.logger.debug(
      `Full system: generating ${totalColumns} columns from selections`,
    );

    // Tüm kombinasyonları üret
    const columns: GeneratedColumn[] = [];
    this.generateCombinations(orderedSelections, 0, "", columns);

    return columns;
  }

  /**
   * İndirgenmiş Sistem Kolon Üretimi
   * Tam sistemdeki kolonlardan rastgele veya stratejik olarak seçim yapar.
   * maxColumns kadar kolon üretir.
   */
  generateReducedSystem(
    matchSelections: TotoMatchSelectionInput[],
    maxColumns: number,
  ): GeneratedColumn[] {
    const fullColumns = this.generateFullSystem(matchSelections);

    if (fullColumns.length <= maxColumns) {
      return fullColumns;
    }

    // Fisher-Yates shuffle ile rastgele seçim
    const shuffled = [...fullColumns];
    for (let i = shuffled.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
    }

    this.logger.debug(
      `Reduced system: ${fullColumns.length} → ${maxColumns} columns`,
    );
    return shuffled.slice(0, maxColumns);
  }

  /**
   * Kolon maliyetini hesapla
   * Spor Toto birim fiyat: 1 TL/kolon (2026 itibarıyla)
   */
  calculateCost(columnCount: number, unitPrice = 1): number {
    return columnCount * unitPrice;
  }

  /**
   * Kolon sayısını hesapla (sistem üretmeden)
   */
  calculateColumnCount(matchSelections: TotoMatchSelectionInput[]): number {
    const selectionsMap = new Map<number, string[]>();
    matchSelections.forEach((ms) => {
      selectionsMap.set(ms.matchOrder, ms.selections);
    });

    let total = 1;
    for (let i = 1; i <= 15; i++) {
      const sel = selectionsMap.get(i);
      total *= sel && sel.length > 0 ? sel.length : 1;
    }
    return total;
  }

  /**
   * Kolonları sonuçlarla karşılaştır
   * @param columns Kolon tahminleri
   * @param results Gerçek sonuçlar (15 karakter: 1/X/2)
   * @returns Her kolon için doğru tahmin sayısı
   */
  evaluateColumns(
    columns: GeneratedColumn[],
    results: string,
  ): { predictions: string; correctCount: number }[] {
    return columns.map((col) => {
      let correct = 0;
      for (let i = 0; i < 15; i++) {
        if (col.predictions[i] === results[i]) {
          correct++;
        }
      }
      return { predictions: col.predictions, correctCount: correct };
    });
  }

  /**
   * Recursive kombinasyon üretici
   */
  private generateCombinations(
    selections: string[][],
    index: number,
    current: string,
    result: GeneratedColumn[],
  ): void {
    if (index === selections.length) {
      result.push({ predictions: current });
      return;
    }

    for (const sel of selections[index]) {
      this.generateCombinations(selections, index + 1, current + sel, result);
    }
  }
}
