#!/usr/bin/env dart

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

import 'package:logger/web.dart';

/// Converts Flutter JSON test results to JUnit XML format
/// Usage: dart test_runner.dart [test_results.json] [output.xml]
void main(List<String> arguments) {
  var logger = Logger(
    printer: PrettyPrinter(methodCount: 2, errorMethodCount: 8, colors: true, printEmojis: true, dateTimeFormat: DateTimeFormat.onlyTimeAndSinceStart),
  );
  if (arguments.length < 2) {
    logger.i('Usage: dart test_runner.dart <json_file> <xml_output>');
    exit(1);
  }

  final jsonFile = arguments[0];
  final xmlFile = arguments[1];

  try {
    final jsonContent = File(jsonFile).readAsStringSync();
    final lines = jsonContent.trim().split('\n');

    final tests = <TestResult>[];
    int totalTests = 0;
    int failures = 0;
    int skipped = 0;
    double duration = 0.0;

    // Parse JSON lines from flutter test output
    for (final line in lines) {
      if (line.trim().isEmpty) continue;

      try {
        final data = jsonDecode(line) as Map<String, dynamic>;
        final type = data['type'] as String?;

        if (type == 'testStart') {
          final test = data['test'] as Map<String, dynamic>;
          final name = test['name'] as String;
          final id = test['id'] as int;
          tests.add(TestResult(id: id, name: name));
          totalTests++;
        } else if (type == 'testDone') {
          final testId = data['testID'] as int;
          final result = data['result'] as String;
          final time = data['time'] as int? ?? 0;
          final error = data['error'] as String?;
          final stackTrace = data['stackTrace'] as String?;

          duration += time / 1000.0; // Convert to seconds

          final testIndex = tests.indexWhere((t) => t.id == testId);
          if (testIndex != -1) {
            tests[testIndex].result = result;
            tests[testIndex].duration = time / 1000.0;
            tests[testIndex].error = error;
            tests[testIndex].stackTrace = stackTrace;

            if (result == 'error' || result == 'failure') {
              failures++;
            } else if (result == 'skip') {
              skipped++;
            }
          }
        }
      } catch (e) {
        // Skip malformed JSON lines
        logger.i('Warning: Could not parse line: $line');
      }
    }

    // Generate JUnit XML
    final xml = generateJUnitXML(tests, totalTests, failures, skipped, duration);
    File(xmlFile).writeAsStringSync(xml);

    logger.i('Converted ${tests.length} test results to JUnit XML: $xmlFile');

    // Exit with error code if there were failures
    if (failures > 0) {
      exit(1);
    }
  } catch (e) {
    logger.e('Error: $e');
    exit(1);
  }
}

class TestResult {
  final int id;
  final String name;
  String result = 'pending';
  double duration = 0.0;
  String? error;
  String? stackTrace;

  TestResult({required this.id, required this.name});
}

String generateJUnitXML(List<TestResult> tests, int total, int failures, int skipped, double duration) {
  final buffer = StringBuffer();

  buffer.writeln('<?xml version="1.0" encoding="UTF-8"?>');
  buffer.writeln('<testsuite name="Flutter Tests" tests="$total" failures="$failures" skipped="$skipped" time="$duration">');

  for (final test in tests) {
    final escapedName = _escapeXml(test.name);
    buffer.writeln('  <testcase name="$escapedName" time="${test.duration}">');

    if (test.result == 'error' || test.result == 'failure') {
      final escapedError = _escapeXml(test.error ?? 'Test failed');
      final escapedStackTrace = _escapeXml(test.stackTrace ?? '');

      buffer.writeln('    <failure message="$escapedError">');
      buffer.writeln('      <![CDATA[$escapedStackTrace]]>');
      buffer.writeln('    </failure>');
    } else if (test.result == 'skip') {
      buffer.writeln('    <skipped/>');
    }

    buffer.writeln('  </testcase>');
  }

  buffer.writeln('</testsuite>');
  return buffer.toString();
}

String _escapeXml(String text) {
  return text.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;').replaceAll('"', '&quot;').replaceAll("'", '&apos;');
}
