// ignore_for_file: avoid_print
import 'dart:convert';
import 'dart:io';

/// Fetches the latest exchange rates from the European Central Bank (ECB)
/// and generates [lib/models/default_exchange_rates.g.dart] with the updated
/// default values.
///
/// Usage:
///   dart run tool/generate_exchange_rates.dart
///
/// If the ECB API is unreachable, the existing generated file is preserved
/// and a warning is printed.
void main() async {
  const currencies = [
    'AUD',
    'BRL',
    'CAD',
    'CHF',
    'CNY',
    'CZK',
    'DKK',
    'GBP',
    'HKD',
    'HUF',
    'IDR',
    'ILS',
    'INR',
    'ISK',
    'JPY',
    'KRW',
    'MXN',
    'MYR',
    'NOK',
    'NZD',
    'PHP',
    'PLN',
    'RON',
    'SEK',
    'SGD',
    'THB',
    'TRY',
    'USD',
    'ZAR',
  ];

  final outputFile = File('lib/models/default_exchange_rates.g.dart');

  print('Fetching exchange rates from ECB...');

  final uri = Uri.https(
    'data-api.ecb.europa.eu',
    'service/data/EXR/D.${currencies.join('+')}.EUR.SP00.A',
    {'lastNObservations': '1', 'detail': 'dataonly', 'format': 'csvdata'},
  );

  try {
    final client = HttpClient();
    final request = await client.getUrl(uri);
    final response = await request.close();

    if (response.statusCode != 200) {
      _handleError(
        'ECB API returned status ${response.statusCode}',
        outputFile,
      );
      return;
    }

    final body = await response.transform(utf8.decoder).join();
    client.close();

    final exchangeRates = <String, double>{'EUR': 1.0};
    final rows = body
        .split('\n')
        .map((r) => r.trim())
        .where((r) => r.isNotEmpty)
        .toList();
    final tableHeader = rows[0].split(',');
    final valueIndex = tableHeader.indexOf('OBS_VALUE');
    final currencyIndex = tableHeader.indexOf('CURRENCY');

    if (valueIndex == -1 || currencyIndex == -1) {
      _handleError(
        'Unexpected CSV format from ECB API',
        outputFile,
      );
      return;
    }

    for (var i = 1; i < rows.length; i++) {
      final elements = rows[i].split(',');
      final currency = elements[currencyIndex];
      final value = double.parse(elements[valueIndex]);
      exchangeRates[currency] = value;
    }

    // Verify we got all expected currencies
    for (final currency in currencies) {
      if (!exchangeRates.containsKey(currency)) {
        print('WARNING: Missing rate for $currency, skipping generation.');
        _handleError(
          'Missing rate for $currency in ECB response',
          outputFile,
        );
        return;
      }
    }

    final now = DateTime.now();
    final dateStr =
        '${now.year}-${now.month.toString().padLeft(2, '0')}-${now.day.toString().padLeft(2, '0')}';

    // Build the generated file content
    final buffer = StringBuffer()
      ..writeln('// GENERATED FILE - DO NOT EDIT')
      ..writeln('// Generated by tool/generate_exchange_rates.dart')
      ..writeln('// Last updated: $dateStr')
      ..writeln()
      ..writeln(
          '/// Default exchange rates relative to EUR, fetched from ECB at build time.')
      ..writeln('const defaultExchangeRates = <String, double>{');

    // Write EUR first, then alphabetically
    buffer.writeln("  'EUR': 1.0,");
    final sortedKeys = exchangeRates.keys
        .where((k) => k != 'EUR')
        .toList()
      ..sort();
    for (final key in sortedKeys) {
      buffer.writeln("  '$key': ${exchangeRates[key]},");
    }
    buffer
      ..writeln('};')
      ..writeln()
      ..writeln('/// Date when these rates were fetched.')
      ..writeln("const defaultExchangeRatesDate = '$dateStr';")
      ..writeln();

    outputFile.writeAsStringSync(buffer.toString());
    print('✓ Generated ${outputFile.path} with ${exchangeRates.length} '
        'currencies (date: $dateStr)');
  } catch (e) {
    _handleError(e.toString(), outputFile);
  }
}

void _handleError(String message, File outputFile) {
  print('WARNING: Failed to fetch exchange rates: $message');
  if (outputFile.existsSync()) {
    print('Keeping existing ${outputFile.path}');
  } else {
    print('ERROR: No existing ${outputFile.path} found. '
        'The build will fail without this file.');
    exit(1);
  }
}
