import 'dart:io';
import 'dart:convert';

import '../../../print.dart';

abstract class LingoHunter {
  /// Extracts translatable strings...
  static Future<void> extractAndCreateTranslationFiles({
    required String baseLang,
    required List<String> langs,
    String? projectDirectory,
    String? outputDirectory,
    bool translateBaseLang = true,
    List<RegExp>? additionalRegExps,
    bool overrideRegExps = false,
    List<String> fileExtensions = const ['.dart'],
  }) async {
    // 1. Find project root (improved logic)
    String projectRoot;
    if (projectDirectory != null) {
      // Use provided directory, but check if it's valid
      if (!await Directory(projectDirectory).exists()) {
        throw ArgumentError(
            "The provided projectDirectory '$projectDirectory' does not exist.");
      }
      projectRoot = projectDirectory;
    } else {
      projectRoot = await _findProjectRoot(); // Use the corrected function
    }

    // 2. Use the project root as output directory if not specified
    final String outputDir = outputDirectory ?? projectRoot;

    // 3. Output Directory Verification (Create if necessary)
    final Directory outputDirObj = Directory(outputDir);
    if (!await outputDirObj.exists()) {
      try {
        await outputDirObj.create(recursive: true);
      } catch (e) {
        throw Exception(
            "Failed to create output directory: $outputDir. Error: $e");
      }
    }

    print("Project root directory: $projectRoot");
    print("Output directory: $outputDir");

    // 4. Extract translatable strings
    final Set<String> strings = await extractStringsFromFlutterProject(
      directory: projectRoot, // Use the validated projectRoot
      additionalRegExps: additionalRegExps,
      overrideRegExps: overrideRegExps,
      fileExtensions: fileExtensions,
    );

    // 5. Generate translation files
    await _createTranslationFiles(
      strings: strings,
      outputDirectory: outputDir,
      baseLang: baseLang,
      langs: langs,
      translateBaseLang: translateBaseLang,
    );

    print("Successfully extracted strings and generated translation files.");
  }

  /// Finds the project's root directory (corrected)
  static Future<String> _findProjectRoot() async {
    Directory current = Directory.current;
    int maxIterations = 10; // Prevent infinite loop
    int count = 0;

    while (count < maxIterations) {
      if (await File('${current.path}/pubspec.yaml').exists()) {
        return current.path; // Return the directory *containing* pubspec.yaml
      }

      if (current.path == current.parent.path) {
        break; // Reached root, stop searching
      }

      current = current.parent;
      count++;
    }

    // If `pubspec.yaml` was not found, throw an exception
    throw Exception(
        "`pubspec.yaml` not found in the current directory or its parents.");
  }

  /// Extracts translatable strings (no changes needed here)
  static Future<Set<String>> extractStringsFromFlutterProject({
    required String directory,
    List<RegExp>? additionalRegExps,
    bool overrideRegExps = false,
    List<String> fileExtensions = const ['.dart'],
  }) async {
    // ... (rest of the function remains the same) ...
    final List<RegExp> defaultPatterns = [
      RegExp(r'"([^"]+)"\.tr\(\)'), // "string".tr()
      RegExp(r"'([^']+)'\.tr\(\)"), // 'string'.tr()
      RegExp(r'"([^"]+)"\.tr'), // "string".tr
      RegExp(r"'([^']+)'\.tr"), // 'string'.tr
      RegExp(r'"([^"]+)"\.tr\(\w+\)'), // "string".tr(context)
      RegExp(r"'([^']+)'\.tr\(\w+\)"), // 'string'.tr(context)
      RegExp(r'context\.tr\("([^"]+)"\)'), // context.tr("string")
      RegExp(r"context\.tr\('([^']+)'\)"), // context.tr('string')
      RegExp(r'tr\(\w+, "([^"]+)"\)'), // tr(context, "string")
      RegExp(r"tr\(\w+, '([^']+)'\)"), // tr(context, 'string')
      RegExp(r'tr\("([^"]+)"\)'), // tr("string")
      RegExp(r"tr\('([^']+)'\)"), // tr('string')
      RegExp(r'"([^"]+)"\.tr\(args: \[.*?\]\)'), // "string".tr(args: [])
      RegExp(r'"([^"]+)"\.plural\(\d+\)'), // "string".plural(3)
      //Intl Package Patterns
      RegExp(r'AppLocalizations\.of\(context\)!\.translate\("([^"]+)"\)'),
    ];

    // Determine the patterns to use
    List<RegExp> patterns;
    if (overrideRegExps && additionalRegExps != null) {
      patterns = additionalRegExps;
    } else {
      patterns = [...defaultPatterns];
      if (additionalRegExps != null) {
        patterns.addAll(additionalRegExps);
      }
    }

    final Set<String> strings = {};
    final Directory projectDirObj = Directory(directory);

    // Check if the directory exists *before* listing
    if (!await projectDirObj.exists()) {
      throw ArgumentError("The directory '$directory' does not exist.");
    }

    final List<FileSystemEntity> entities =
        await projectDirObj.list(recursive: true).toList();

    // Filter files by the specified extensions
    final List<File> filteredFiles = entities
        .whereType<File>()
        .where((file) => fileExtensions.any((ext) => file.path.endsWith(ext)))
        .toList();

    // Extract strings from files
    for (final File file in filteredFiles) {
      final String content = await file.readAsString();

      for (final RegExp pattern in patterns) {
        final Iterable<RegExpMatch> matches = pattern.allMatches(content);

        for (final RegExpMatch match in matches) {
          if (match.groupCount >= 1 && match.group(1) != null) {
            strings.add(match.group(1)!);
          }
        }
      }
    }

    return strings;
  }

  /// Creates translation files (no changes needed)
  static Future<void> _createTranslationFiles({
    required Set<String> strings,
    required String outputDirectory,
    required String baseLang,
    required List<String> langs,
    bool translateBaseLang = true,
  }) async {
    // ... (rest of the function remains the same) ...
    final Directory outputDir = Directory(outputDirectory);
    if (!await outputDir.exists()) {
      Log.print('outputDir: ${outputDir}');
      await outputDir.create(recursive: true);
    }

    // Always create the base language file, even if `translateBaseLang` is false
    final String baseFilePath = '$outputDirectory/translations_$baseLang.json';
    final Map<String, String> baseStrings = {
      for (final string in strings) string: translateBaseLang ? string : ""
    };
    await _writeTranslationFile(baseFilePath, baseStrings);

    for (final String lang in langs) {
      final String langFilePath = '$outputDirectory/translations_$lang.json';
      final Map<String, String> langStrings = {
        for (final string in strings) string: ""
      };
      await _writeTranslationFile(langFilePath, langStrings);
    }
  }

  /// Writes a translation file (no changes needed)
  static Future<void> _writeTranslationFile(
      String filePath, Map<String, String> strings) async {
    // ... (rest of the function remains the same) ...
    final File file = File(filePath);
    final StringBuffer content = StringBuffer();
    content.writeln('{');

    int index = 0;
    for (final MapEntry<String, String> entry in strings.entries) {
      final String comma = (index < strings.length - 1) ? ',' : '';
      final String key =
          jsonEncode(entry.key).substring(1, jsonEncode(entry.key).length - 1);
      final String value = entry.value.isEmpty
          ? ""
          : jsonEncode(entry.value)
              .substring(1, jsonEncode(entry.value).length - 1);

      content.writeln('    "$key": "$value"$comma');
      index++;
    }

    content.writeln('}');
    await file.writeAsString(content.toString());
  }
}
