import 'business_day_util.dart';

/// 결제 주기 및 결제일 계산 유틸리티
class BillingDateUtil {
  /// 결제 주기를 표준 키로 정규화합니다.
  /// 반환값 예: 'monthly' | 'quarterly' | 'half-yearly' | 'yearly' | 'weekly'
  static String normalizeCycle(String cycle) {
    final c = cycle.trim().toLowerCase();

    // 영어 우선 매핑
    if (c.contains('monthly')) return 'monthly';
    if (c.contains('quarter')) return 'quarterly';
    if (c.contains('half') || c.contains('half-year')) return 'half-yearly';
    if (c.contains('year')) return 'yearly';
    if (c.contains('week')) return 'weekly';

    // 한국어
    if (cycle.contains('매월') || cycle.contains('월간')) return 'monthly';
    if (cycle.contains('분기')) return 'quarterly';
    if (cycle.contains('반기')) return 'half-yearly';
    if (cycle.contains('매년') || cycle.contains('연간')) return 'yearly';
    if (cycle.contains('주간')) return 'weekly';

    // 일본어
    if (cycle.contains('毎月')) return 'monthly';
    if (cycle.contains('四半期')) return 'quarterly';
    if (cycle.contains('半年')) return 'half-yearly';
    if (cycle.contains('年間')) return 'yearly';
    if (cycle.contains('週間')) return 'weekly';

    // 중국어(간체/번체 공통 표현 대응)
    if (cycle.contains('每月')) return 'monthly';
    if (cycle.contains('每季度')) return 'quarterly';
    if (cycle.contains('每半年')) return 'half-yearly';
    if (cycle.contains('每年')) return 'yearly';
    if (cycle.contains('每周') || cycle.contains('每週')) return 'weekly';

    // 기본값
    return 'monthly';
  }

  /// 선택된 날짜가 오늘(또는 과거)이면, 결제 주기에 맞춰 다음 회차 날짜로 보정합니다.
  /// 이미 미래라면 해당 날짜를 그대로 반환합니다.
  static DateTime ensureFutureDate(DateTime selected, String cycle) {
    final normalized = normalizeCycle(cycle);
    final selectedDateOnly =
        DateTime(selected.year, selected.month, selected.day);
    final now = DateTime.now();
    final today = DateTime(now.year, now.month, now.day);

    if (selectedDateOnly.isAfter(today)) return selectedDateOnly;

    DateTime next = selectedDateOnly;
    switch (normalized) {
      case 'weekly':
        while (!next.isAfter(today)) {
          next = next.add(const Duration(days: 7));
        }
        break;
      case 'quarterly':
        while (!next.isAfter(today)) {
          next = _addMonthsClamped(next, 3);
        }
        break;
      case 'half-yearly':
        while (!next.isAfter(today)) {
          next = _addMonthsClamped(next, 6);
        }
        break;
      case 'yearly':
        while (!next.isAfter(today)) {
          next = _addYearsClamped(next, 1);
        }
        break;
      case 'monthly':
      default:
        while (!next.isAfter(today)) {
          next = _addMonthsClamped(next, 1);
        }
        break;
    }

    return next;
  }

  /// month 단위 가산 시, 대상 월의 말일을 넘지 않도록 day를 클램프합니다.
  static DateTime _addMonthsClamped(DateTime base, int months) {
    final totalMonths = base.month - 1 + months;
    final year = base.year + totalMonths ~/ 12;
    final month = totalMonths % 12 + 1;
    final dim = BusinessDayUtil.daysInMonth(year, month);
    final day = base.day.clamp(1, dim);
    return DateTime(year, month, day);
  }

  /// year 단위 가산 시, 대상 월의 말일을 넘지 않도록 day를 클램프합니다.
  static DateTime _addYearsClamped(DateTime base, int years) {
    final year = base.year + years;
    final dim = BusinessDayUtil.daysInMonth(year, base.month);
    final day = base.day.clamp(1, dim);
    return DateTime(year, base.month, day);
  }
}
