/// Parses recurrence-rule strings produced by the `rrule_generator` widget
/// into a clean RRULE plus a separate list of exception dates.
///
/// `rrule_generator` appends excluded dates as `;EXDATE=20260514T000000,...`
/// to the rule string, which is **not** valid iCalendar — `EXDATE` is its
/// own property, not an RRULE parameter. Anything reading the raw string
/// with a strict parser (Syncfusion, package:rrule) silently drops the
/// EXDATE bit, so exclusions never apply. Split the two here.
class ParsedRRule {
  final String rule;
  final List<DateTime> exceptions;
  const ParsedRRule({required this.rule, required this.exceptions});

  static const empty = ParsedRRule(rule: '', exceptions: []);
}

ParsedRRule parseRRuleWithExceptions(String input) {
  if (input.isEmpty) return ParsedRRule.empty;
  final match = RegExp(r';EXDATE=([^;]+)$').firstMatch(input);
  final exceptions = match == null
      ? const <DateTime>[]
      : match
            .group(1)!
            .split(',')
            .map(_parseExdate)
            .whereType<DateTime>()
            .toList();
  // Keep the rule string as-is (still has its `RRULE:` content-line prefix
  // when present). Both Syncfusion's `Appointment.recurrenceRule` and
  // `package:rrule`'s `RecurrenceRule.fromString` parse it correctly with
  // the prefix; stripping it was a regression that confused Syncfusion's
  // weekly BYDAY decoder on multi-day rules.
  final rule = match == null ? input : input.substring(0, match.start);
  return ParsedRRule(rule: rule, exceptions: exceptions);
}

/// Parses one `yyyyMMddTHHmmss` chunk into a local-time [DateTime].
DateTime? _parseExdate(String s) {
  if (s.length < 15 || s[8] != 'T') return null;
  final year = int.tryParse(s.substring(0, 4));
  final month = int.tryParse(s.substring(4, 6));
  final day = int.tryParse(s.substring(6, 8));
  final hour = int.tryParse(s.substring(9, 11));
  final minute = int.tryParse(s.substring(11, 13));
  final second = int.tryParse(s.substring(13, 15));
  if ([
    year,
    month,
    day,
    hour,
    minute,
    second,
  ].any((e) => e == null)) {
    return null;
  }
  return DateTime(year!, month!, day!, hour!, minute!, second!);
}
