import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:timezone/data/latest_all.dart' as tz;
import 'package:timezone/timezone.dart' as tz;

import 'package:household_keeper/core/notifications/notification_service.dart';

void main() {
  setUpAll(() {
    tz.initializeTimeZones();
    tz.setLocalLocation(tz.getLocation('Europe/Berlin'));
  });

  group('NotificationService', () {
    test('singleton pattern: two instances are identical', () {
      final a = NotificationService();
      final b = NotificationService();
      expect(identical(a, b), isTrue);
    });

    group('nextInstanceOf', () {
      test('returns today when time is in the future', () {
        final service = NotificationService();
        final now = tz.TZDateTime.now(tz.local);

        // Use a time 2 hours in the future, wrapping midnight if needed
        final futureHour = (now.hour + 2) % 24;
        final futureMinute = now.minute;
        final futureTime = TimeOfDay(hour: futureHour, minute: futureMinute);

        // Only test this case if futureHour > now.hour (no midnight wrap)
        if (futureHour > now.hour) {
          final result = service.nextInstanceOf(futureTime);
          expect(result.day, now.day);
          expect(result.hour, futureHour);
          expect(result.minute, futureMinute);
        }
      });

      test('returns tomorrow when time has passed', () {
        final service = NotificationService();
        final now = tz.TZDateTime.now(tz.local);

        // Use a time in the past (1 hour ago), wrapping to previous day if needed
        final pastHour = now.hour - 1;

        // Only test if we are not at the beginning of the day
        if (pastHour >= 0) {
          final pastTime = TimeOfDay(hour: pastHour, minute: 0);
          final result = service.nextInstanceOf(pastTime);
          expect(result.day, now.day + 1);
          expect(result.hour, pastHour);
          expect(result.minute, 0);
        }
      });

      test('scheduled time is in the future (always)', () {
        final service = NotificationService();
        final now = tz.TZDateTime.now(tz.local);

        // Test with midnight (00:00) — always results in a time in future (tomorrow)
        final result = service.nextInstanceOf(const TimeOfDay(hour: 0, minute: 0));

        expect(result.isAfter(now) || result.isAtSameMomentAs(now), isTrue);
      });

      test('nextInstanceOf respects hours and minutes exactly', () {
        final service = NotificationService();
        final now = tz.TZDateTime.now(tz.local);

        // Use a far future time today: 23:59, which should be today if we are before it
        const targetTime = TimeOfDay(hour: 23, minute: 59);
        final todayTarget = tz.TZDateTime(
          tz.local,
          now.year,
          now.month,
          now.day,
          23,
          59,
        );

        final result = service.nextInstanceOf(targetTime);

        if (now.isBefore(todayTarget)) {
          expect(result.hour, 23);
          expect(result.minute, 59);
          expect(result.day, now.day);
        } else {
          // After 23:59, scheduled for tomorrow
          expect(result.hour, 23);
          expect(result.minute, 59);
          expect(result.day, now.day + 1);
        }
      });
    });
  });
}
