import 'dart:collection';

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:habo/habits/habit.dart';
import 'package:habo/habits/habits_manager.dart';
import 'package:habo/model/habit_data.dart';
import 'package:habo/repositories/habit_repository.dart';
import 'package:habo/repositories/event_repository.dart';
import 'package:habo/repositories/category_repository.dart';
import 'package:habo/services/backup_service.dart';
import 'package:habo/services/notification_service.dart';
import 'package:habo/services/ui_feedback_service.dart';
import 'package:habo/generated/l10n.dart';
import 'package:mocktail/mocktail.dart';

class MockHabitRepository extends Mock implements HabitRepository {}

class MockEventRepository extends Mock implements EventRepository {}

class MockCategoryRepository extends Mock implements CategoryRepository {}

class MockBackupService extends Mock implements BackupService {}

class MockNotificationService extends Mock implements NotificationService {}

class MockUIFeedbackService extends Mock implements UIFeedbackService {}

void main() {
  late HabitsManager habitsManager;
  late MockHabitRepository mockHabitRepository;
  late MockEventRepository mockEventRepository;
  late MockCategoryRepository mockCategoryRepository;
  late MockBackupService mockBackupService;
  late MockNotificationService mockNotificationService;
  late MockUIFeedbackService mockUIFeedbackService;

  setUp(() {
    mockHabitRepository = MockHabitRepository();
    mockEventRepository = MockEventRepository();
    mockCategoryRepository = MockCategoryRepository();
    mockBackupService = MockBackupService();
    mockNotificationService = MockNotificationService();
    mockUIFeedbackService = MockUIFeedbackService();

    habitsManager = HabitsManager(
      habitRepository: mockHabitRepository,
      eventRepository: mockEventRepository,
      categoryRepository: mockCategoryRepository,
      backupService: mockBackupService,
      notificationService: mockNotificationService,
      // Don't pass uiFeedbackService to avoid localization
    );
  });

  setUpAll(() {
    TestWidgetsFlutterBinding.ensureInitialized();
    registerFallbackValue(Habit(
      habitData: HabitData(
        position: 0,
        title: 'Fallback',
        twoDayRule: false,
        cue: '',
        routine: '',
        reward: '',
        showReward: false,
        advanced: false,
        notification: false,
        notTime: const TimeOfDay(hour: 9, minute: 0),
        events: SplayTreeMap<DateTime, List>(),
        sanction: '',
        showSanction: false,
        accountant: '',
      ),
    ));
    registerFallbackValue(TimeOfDay.now());
    registerFallbackValue(Colors.grey);

    // Initialize localization for tests
    S.load(const Locale('en'));
  });

  group('HabitsManager with Repository Pattern', () {
    test('should initialize with provided repositories', () {
      expect(habitsManager, isNotNull);
    });

    test('should load habits from repository', () async {
      // Setup
      final testHabit = Habit(
        habitData: HabitData(
          position: 0,
          title: 'Test Habit',
          twoDayRule: false,
          cue: 'Test cue',
          routine: 'Test routine',
          reward: 'Test reward',
          showReward: false,
          advanced: false,
          notification: false,
          notTime: const TimeOfDay(hour: 9, minute: 0),
          events: SplayTreeMap<DateTime, List>(),
          sanction: '',
          showSanction: false,
          accountant: '',
        ),
      );

      when(() => mockHabitRepository.getAllHabits())
          .thenAnswer((_) async => [testHabit]);

      // Act
      await habitsManager.initModel();

      // Assert
      verify(() => mockHabitRepository.getAllHabits()).called(1);
      expect(habitsManager.allHabits.length, 1);
      expect(habitsManager.allHabits[0].habitData.title, 'Test Habit');
    });

    test('should add habit through repository', () async {
      // Setup
      when(() => mockHabitRepository.createHabit(any()))
          .thenAnswer((_) async => 1);
      when(() => mockHabitRepository.getAllHabits())
          .thenAnswer((_) async => []);

      // Act
      habitsManager.addHabit(
        'New Habit',
        false,
        'Test cue',
        'Test routine',
        'Test reward',
        false,
        false,
        false,
        const TimeOfDay(hour: 9, minute: 0),
        'Test sanction',
        false,
        'Test accountant',
      );

      // Assert
      verify(() => mockHabitRepository.createHabit(any())).called(1);
    });

    test('should update habit through repository', () async {
      // Setup
      final testHabit = Habit(
        habitData: HabitData(
          id: 1,
          position: 0,
          title: 'Original',
          twoDayRule: false,
          cue: '',
          routine: '',
          reward: '',
          showReward: false,
          advanced: false,
          notification: false,
          notTime: const TimeOfDay(hour: 9, minute: 0),
          events: SplayTreeMap<DateTime, List>(),
          sanction: '',
          showSanction: false,
          accountant: '',
        ),
      );

      // Add habit to internal state
      habitsManager.allHabits.add(testHabit);
      when(() => mockHabitRepository.updateHabit(any()))
          .thenAnswer((_) async {});

      // Act
      habitsManager.editHabit(testHabit.habitData);

      // Assert
      verify(() => mockHabitRepository.updateHabit(any())).called(1);
    });

    test('should delete habit through repository', () async {
      // Setup
      final testHabit = Habit(
        habitData: HabitData(
          id: 1,
          position: 0,
          title: 'Test Habit',
          twoDayRule: false,
          cue: '',
          routine: '',
          reward: '',
          showReward: false,
          advanced: false,
          notification: false,
          notTime: const TimeOfDay(hour: 9, minute: 0),
          events: SplayTreeMap<DateTime, List>(),
          sanction: '',
          showSanction: false,
          accountant: '',
        ),
      );

      // Add habit to internal state
      habitsManager.allHabits.add(testHabit);
      when(() => mockHabitRepository.deleteHabit(any()))
          .thenAnswer((_) async {});
      // Mock specific localization strings
      when(() => mockUIFeedbackService.showMessageWithAction(
            message: any(named: 'message'),
            actionLabel: any(named: 'actionLabel'),
            onActionPressed: any(named: 'onActionPressed'),
            backgroundColor: any(named: 'backgroundColor'),
          )).thenReturn(null);

      // Act
      habitsManager.deleteHabit(1);

      // Assert - verify internal state changes immediately
      expect(habitsManager.allHabits.length, 0);
      expect(habitsManager.toDelete.length, 1);
    });
  });
}
