import fs from 'fs';
import path from 'path';
import { ko } from '../src/i18n/locales/ko';
import { en } from '../src/i18n/locales/en';

/**
 * 전역 설정 및 상수
 */
const TARGET_DIR = path.join(__dirname, '../tests');
const IGNORE_FILES = ['node_modules', '.git'];
const LOCALES = { ko, en };

type I18nEntry = { key: string; locales: string[] };
const i18nValueToKey = new Map<string, I18nEntry>();

/**
 * i18n 객체를 평탄화하여 '값 -> 키' 매핑을 생성합니다.
 */
function walk(obj: any, prefix = '', locale = '') {
  for (const [key, value] of Object.entries(obj)) {
    const fullKey = prefix ? `${prefix}.${key}` : key;
    if (typeof value === 'string') {
      const entry = i18nValueToKey.get(value);
      if (entry) {
        if (!entry.locales.includes(locale)) entry.locales.push(locale);
      } else {
        i18nValueToKey.set(value, { key: fullKey, locales: [locale] });
      }
    } else if (typeof value === 'object' && value !== null) {
      walk(value, fullKey, locale);
    }
  }
}

// 로딩
for (const [locale, data] of Object.entries(LOCALES)) {
  walk(data, '', locale);
}

/**
 * 테스트 파일을 재귀적으로 탐색합니다.
 */
function getFiles(dir: string): string[] {
  const results: string[] = [];
  if (!fs.existsSync(dir)) return results;

  const list = fs.readdirSync(dir);
  for (const file of list) {
    if (IGNORE_FILES.some(ignore => file.includes(ignore))) continue;
    const fullPath = path.join(dir, file);
    const stat = fs.statSync(fullPath);
    if (stat.isDirectory()) {
      results.push(...getFiles(fullPath));
    } else if (file.endsWith('.test.ts') || file.endsWith('.spec.ts') || (dir.includes('tests') && file.endsWith('.ts'))) {
      results.push(fullPath);
    }
  }
  return results;
}

/**
 * 파일 내에서 하드코딩된 i18n 값을 찾습니다.
 */
function checkFile(filePath: string) {
  const content = fs.readFileSync(filePath, 'utf-8');
  const lines = content.split('\n');
  let matchCount = 0;

  lines.forEach((line, index) => {
    // 0. 무시 주석 체크
    if (line.includes('i18n-ignore')) return;

    // 따옴표로 둘러싸인 모든 문자열을 찾습니다.
    // 인덱스를 추적하기 위해 수동으로 문자열을 찾습니다.
    const regex = /(['"`])(.*?)\1/g;
    let match;
    while ((match = regex.exec(line)) !== null) {
      const fullMatch = match[0];
      const val = match[2];

      if (i18nValueToKey.has(val)) {
        const info = i18nValueToKey.get(val)!;
        
        // 1. 만약 문자열이 i18n 키 자체라면 (점 포함) 무시합니다.
        if (val === info.key || (val.includes('.') && !val.includes(' '))) continue;

        // 2. t(..., 'key') 에서 'key'가 값과 같은 경우 무시 (매우 드문 경우)
        // t() 호출 안에 있는지 대략적으로 체크
        const linePrefix = line.substring(0, match.index);
        if (linePrefix.trim().endsWith('t(') || linePrefix.includes('t(')) {
          // 호출 인자로 보인다면 패스 (단순화된 로직)
          if (val === info.key) continue;
        }

        console.log(`[FOUND] ${path.relative(process.cwd(), filePath)}:${index + 1}`);
        console.log(`  - Hardcoded: ${fullMatch}`);
        console.log(`  - Suggested: t(locale, '${info.key}')`);
        console.log(`  - Values: "${val}"`);
        console.log(`  - Locales: ${info.locales.join(', ')}`);
        console.log('');
        matchCount++;
      }
    }
  });

  return matchCount;
}

// 실행
console.log('--- i18n Reference Check in Tests ---');
console.log(`Total i18n values loaded: ${i18nValueToKey.size}`);

const files = getFiles(TARGET_DIR);
console.log(`Checking ${files.length} test files...`);

let totalMatch = 0;
files.forEach(file => {
  totalMatch += checkFile(file);
});

if (totalMatch === 0) {
  console.log('✅ No hardcoded i18n values found in tests.');
} else {
  console.log(`❌ Found ${totalMatch} violations.`);
}
