import 'dart:developer' as dev;
import 'package:flutter_test/flutter_test.dart';
import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_calendar_model.dart';

/// Comprehensive test to analyze date conversion issues between Gregorian and Hijri calendars
/// This test simulates the onDobChange method logic and tests 200 years of dates
void main() {
  group('Date Conversion Analysis - 200 Years', () {
    // Test results storage
    final List<DateConversionResult> results = [];
    final List<String> errors = [];

    test('Test Gregorian to Hijri conversion for 200 years', () {
      print('\n========================================');
      print('GREGORIAN TO HIJRI CONVERSION TEST');
      print('Testing dates from 1925 to 2125 (200 years)');
      print('========================================\n');

      int totalDates = 0;
      int successfulConversions = 0;
      int failedConversions = 0;

      // Test dates from 1925 to 2125 (200 years)
      for (int year = 1925; year <= 2125; year++) {
        // Test all 12 months
        for (int month = 1; month <= 12; month++) {
          // Test key days in each month (1st, 15th, last day)
          final daysToTest = [1, 15, _getLastDayOfMonth(year, month)];

          for (int day in daysToTest) {
            totalDates++;

            try {
              // Create Gregorian date
              final gregorianDate = DateTime(year, month, day);
              final isoString = gregorianDate.toIso8601String();

              // Test parsing (this is where the error occurs)
              final parsedDate = DateTime.parse(isoString);

              // Test Hijri conversion
              final hijriDate = HijriGregConverter.gregorianToHijri(parsedDate);

              // Test creating DateTime from Hijri components
              final hijriDateTime = DateTime(hijriDate.year, hijriDate.month, hijriDate.day);

              // Test formatting methods
              final apiFormat = _formatDateForApi(isoString);
              final displayFormat = _formatDateToDisplay(isoString);
              final hijriDisplayFormat = _formatHijriDateToDisplay(hijriDateTime.toIso8601String());

              // Store successful result
              results.add(DateConversionResult(
                gregorianDate: gregorianDate,
                isoString: isoString,
                hijriYear: hijriDate.year,
                hijriMonth: hijriDate.month,
                hijriDay: hijriDate.day,
                apiFormat: apiFormat,
                displayFormat: displayFormat,
                hijriDisplayFormat: hijriDisplayFormat,
                success: true,
              ));

              successfulConversions++;

            } catch (e) {
              failedConversions++;
              final errorMsg = 'ERROR on $year-${month.toString().padLeft(2, '0')}-${day.toString().padLeft(2, '0')}: $e';
              errors.add(errorMsg);
              print(errorMsg);

              results.add(DateConversionResult(
                gregorianDate: DateTime(year, month, day),
                isoString: 'FAILED',
                hijriYear: 0,
                hijriMonth: 0,
                hijriDay: 0,
                apiFormat: 'FAILED',
                displayFormat: 'FAILED',
                hijriDisplayFormat: 'FAILED',
                success: false,
                errorMessage: e.toString(),
              ));
            }
          }
        }

        // Print progress every 10 years
        if (year % 10 == 0) {
          print('Processed up to year $year... (Success: $successfulConversions, Failed: $failedConversions)');
        }
      }

      // Print summary
      print('\n========================================');
      print('TEST SUMMARY');
      print('========================================');
      print('Total dates tested: $totalDates');
      print('Successful conversions: $successfulConversions');
      print('Failed conversions: $failedConversions');
      print('Success rate: ${(successfulConversions / totalDates * 100).toStringAsFixed(2)}%');
      print('========================================\n');

      // Print all errors
      if (errors.isNotEmpty) {
        print('\n========================================');
        print('ALL ERRORS (${errors.length} total):');
        print('========================================');
        for (var error in errors) {
          print(error);
        }
      }

      // Print sample successful conversions
      if (results.where((r) => r.success).isNotEmpty) {
        print('\n========================================');
        print('SAMPLE SUCCESSFUL CONVERSIONS (First 5):');
        print('========================================');
        int count = 0;
        for (var result in results.where((r) => r.success)) {
          if (count >= 5) break;
          print('Gregorian: ${result.gregorianDate}');
          print('  ISO: ${result.isoString}');
          print('  Hijri: ${result.hijriYear}-${result.hijriMonth}-${result.hijriDay}');
          print('  API Format: ${result.apiFormat}');
          print('  Display Format: ${result.displayFormat}');
          print('  Hijri Display: ${result.hijriDisplayFormat}');
          print('---');
          count++;
        }
      }

      // Test should fail if there are any errors
      expect(failedConversions, 0, reason: 'Found $failedConversions failed conversions');
    });

    test('Test specific edge cases', () {
      print('\n========================================');
      print('EDGE CASES TEST');
      print('========================================\n');

      final edgeCases = [
        DateTime(1900, 1, 1), // Very old date
        DateTime(1970, 1, 1), // Unix epoch
        DateTime(2000, 1, 1), // Y2K
        DateTime(2000, 2, 29), // Leap year
        DateTime(2001, 2, 28), // Non-leap year
        DateTime(2024, 12, 31), // Recent date
        DateTime(2025, 1, 1), // Near future
        DateTime(2100, 12, 31), // Far future
        DateTime(2124, 2, 29), // Leap year in far future
        DateTime(2125, 12, 31), // End of test range
      ];

      for (var testDate in edgeCases) {
        try {
          final isoString = testDate.toIso8601String();
          final parsedDate = DateTime.parse(isoString);
          final hijriDate = HijriGregConverter.gregorianToHijri(parsedDate);

          print('✓ ${testDate.toString().split(' ')[0]} -> Hijri: ${hijriDate.year}-${hijriDate.month}-${hijriDate.day}');
        } catch (e) {
          print('✗ ${testDate.toString().split(' ')[0]} -> ERROR: $e');
          fail('Edge case failed: $testDate - $e');
        }
      }
    });

    test('Test DateRangCalenderModel with Umm al-Qura offset', () {
      print('\n========================================');
      print('UMM AL-QURA OFFSET TEST');
      print('========================================\n');

      // We can't fully test DateRangCalenderModel without full context,
      // but we can test the conversion logic

      final testDates = [
        DateTime(2024, 1, 1),
        DateTime(2024, 6, 15),
        DateTime(2024, 12, 31),
        DateTime(2025, 1, 1),
      ];

      for (var testDate in testDates) {
        try {
          // Simulate the Umm al-Qura offset (-1 day)
          final adjustedDate = testDate.subtract(const Duration(days: 1));
          final hijriDate = HijriGregConverter.gregorianToHijri(adjustedDate);

          print('Original: ${testDate.toString().split(' ')[0]}');
          print('  Adjusted (-1 day): ${adjustedDate.toString().split(' ')[0]}');
          print('  Hijri: ${hijriDate.year}-${hijriDate.month}-${hijriDate.day}');
          print('---');
        } catch (e) {
          print('ERROR on ${testDate.toString().split(' ')[0]}: $e');
          fail('Umm al-Qura offset test failed: $testDate - $e');
        }
      }
    });

    test('Test problematic date formats', () {
      print('\n========================================');
      print('PROBLEMATIC DATE FORMATS TEST');
      print('========================================\n');

      final problematicFormats = [
        '2024-01-01T00:00:00.000',
        '2024-01-01T00:00:00.000Z',
        '2024-01-01T00:00:00',
        '2024-01-01',
        '2024-1-1',
        '2024-01-1',
        '2024-1-01',
      ];

      for (var format in problematicFormats) {
        try {
          final parsed = DateTime.parse(format);
          print('✓ Format "$format" parsed successfully: ${parsed.toString()}');
        } catch (e) {
          print('✗ Format "$format" FAILED to parse: $e');
        }
      }
    });
  });
}

// Helper function to get last day of month
int _getLastDayOfMonth(int year, int month) {
  if (month == 12) {
    return DateTime(year + 1, 1, 1).subtract(const Duration(days: 1)).day;
  }
  return DateTime(year, month + 1, 1).subtract(const Duration(days: 1)).day;
}

// Replicate Utils methods for testing
String _formatDateForApi(String isoDateString) {
  try {
    final dateTime = DateTime.parse(isoDateString);
    final year = dateTime.year.toString();
    final month = dateTime.month.toString().padLeft(2, '0');
    final day = dateTime.day.toString().padLeft(2, '0');
    return '$day/$month/$year';
  } catch (e) {
    return 'ERROR: $e';
  }
}

String _formatDateToDisplay(String isoDateString) {
  try {
    final dateTime = DateTime.parse(isoDateString);
    final day = dateTime.day.toString().padLeft(2, '0');
    final year = dateTime.year.toString();
    const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
    final month = monthNames[dateTime.month - 1];
    return '$day $month, $year';
  } catch (e) {
    return 'ERROR: $e';
  }
}

String _formatHijriDateToDisplay(String hijriDateString) {
  try {
    final datePart = hijriDateString.split("T").first;
    final parts = datePart.split('-');
    if (parts.length != 3) return 'ERROR: Invalid format';

    final day = parts[2].padLeft(2, '0');
    final year = parts[0];

    const hijriMonthNames = [
      'Muharram',
      'Safar',
      'Rabi I',
      'Rabi II',
      'Jumada I',
      'Jumada II',
      'Rajab',
      'Sha\'ban',
      'Ramadan',
      'Shawwal',
      'Dhu al-Qi\'dah',
      'Dhu al-Hijjah'
    ];
    final monthIndex = int.tryParse(parts[1]) ?? 1;
    final month = hijriMonthNames[monthIndex - 1];

    return '$day $month, $year';
  } catch (e) {
    return 'ERROR: $e';
  }
}

// Stub for HijriGregConverter (since we're testing the logic)
class HijriGregConverter {
  static HijriGregDate gregorianToHijri(DateTime gregorianDate) {
    // This is a simplified conversion for testing
    // In reality, this would use the actual Hijri calendar library

    // Basic astronomical calculation (not exact Umm al-Qura)
    final julianDay = _gregorianToJulianDay(gregorianDate);
    final hijriDate = _julianDayToHijri(julianDay);

    return hijriDate;
  }

  static int _gregorianToJulianDay(DateTime date) {
    int a = (14 - date.month) ~/ 12;
    int y = date.year + 4800 - a;
    int m = date.month + 12 * a - 3;

    return date.day + (153 * m + 2) ~/ 5 + 365 * y + y ~/ 4 - y ~/ 100 + y ~/ 400 - 32045;
  }

  static HijriGregDate _julianDayToHijri(int julianDay) {
    // Basic conversion (simplified for testing)
    int l = julianDay - 1948440 + 10632;
    int n = (l - 1) ~/ 10631;
    l = l - 10631 * n + 354;
    int j = ((10985 - l) ~/ 5316) * ((50 * l) ~/ 17719) + (l ~/ 5670) * ((43 * l) ~/ 15238);
    l = l - ((30 - j) ~/ 15) * ((17719 * j) ~/ 50) - (j ~/ 16) * ((15238 * j) ~/ 43) + 29;
    int month = (24 * l) ~/ 709;
    int day = l - (709 * month) ~/ 24;
    int year = 30 * n + j - 30;

    return HijriGregDate(year: year, month: month, day: day);
  }
}

class HijriGregDate {
  final int year;
  final int month;
  final int day;

  HijriGregDate({required this.year, required this.month, required this.day});
}

// Data class to store test results
class DateConversionResult {
  final DateTime gregorianDate;
  final String isoString;
  final int hijriYear;
  final int hijriMonth;
  final int hijriDay;
  final String apiFormat;
  final String displayFormat;
  final String hijriDisplayFormat;
  final bool success;
  final String? errorMessage;

  DateConversionResult({
    required this.gregorianDate,
    required this.isoString,
    required this.hijriYear,
    required this.hijriMonth,
    required this.hijriDay,
    required this.apiFormat,
    required this.displayFormat,
    required this.hijriDisplayFormat,
    required this.success,
    this.errorMessage,
  });
}

