import 'package:drift/native.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:household_keeper/core/database/database.dart';
import 'package:household_keeper/features/tasks/domain/effort_level.dart';
import 'package:household_keeper/features/tasks/domain/frequency.dart';

void main() {
  late AppDatabase db;
  late int room1Id;
  late int room2Id;

  setUp(() async {
    db = AppDatabase(NativeDatabase.memory());
    room1Id = await db.roomsDao.insertRoom(
      RoomsCompanion.insert(name: 'Kueche', iconName: 'kitchen'),
    );
    room2Id = await db.roomsDao.insertRoom(
      RoomsCompanion.insert(name: 'Badezimmer', iconName: 'bathroom'),
    );
  });

  tearDown(() async {
    await db.close();
  });

  group('DailyPlanDao.watchAllTasksWithRoomName', () {
    test('returns empty list when no tasks exist', () async {
      final result =
          await db.dailyPlanDao.watchAllTasksWithRoomName().first;
      expect(result, isEmpty);
    });

    test('returns tasks with correct room name from join', () async {
      await db.tasksDao.insertTask(TasksCompanion.insert(
        roomId: room1Id,
        name: 'Abspuelen',
        intervalType: IntervalType.daily,
        effortLevel: EffortLevel.low,
        nextDueDate: DateTime(2026, 3, 16),
      ));

      final result =
          await db.dailyPlanDao.watchAllTasksWithRoomName().first;
      expect(result.length, 1);
      expect(result.first.task.name, 'Abspuelen');
      expect(result.first.roomName, 'Kueche');
      expect(result.first.roomId, room1Id);
    });

    test('returns tasks sorted by nextDueDate ascending', () async {
      await db.tasksDao.insertTask(TasksCompanion.insert(
        roomId: room1Id,
        name: 'Later',
        intervalType: IntervalType.weekly,
        effortLevel: EffortLevel.medium,
        nextDueDate: DateTime(2026, 3, 20),
      ));
      await db.tasksDao.insertTask(TasksCompanion.insert(
        roomId: room1Id,
        name: 'Earlier',
        intervalType: IntervalType.daily,
        effortLevel: EffortLevel.low,
        nextDueDate: DateTime(2026, 3, 10),
      ));
      await db.tasksDao.insertTask(TasksCompanion.insert(
        roomId: room1Id,
        name: 'Middle',
        intervalType: IntervalType.biweekly,
        effortLevel: EffortLevel.high,
        nextDueDate: DateTime(2026, 3, 15),
      ));

      final result =
          await db.dailyPlanDao.watchAllTasksWithRoomName().first;
      expect(result.length, 3);
      expect(result[0].task.name, 'Earlier');
      expect(result[1].task.name, 'Middle');
      expect(result[2].task.name, 'Later');
    });

    test('returns tasks from multiple rooms with correct room name pairing',
        () async {
      await db.tasksDao.insertTask(TasksCompanion.insert(
        roomId: room1Id,
        name: 'Kueche Task',
        intervalType: IntervalType.daily,
        effortLevel: EffortLevel.low,
        nextDueDate: DateTime(2026, 3, 16),
      ));
      await db.tasksDao.insertTask(TasksCompanion.insert(
        roomId: room2Id,
        name: 'Bad Task',
        intervalType: IntervalType.weekly,
        effortLevel: EffortLevel.medium,
        nextDueDate: DateTime(2026, 3, 15),
      ));

      final result =
          await db.dailyPlanDao.watchAllTasksWithRoomName().first;
      expect(result.length, 2);
      // Sorted by due date: Bad Task (Mar 15) before Kueche Task (Mar 16)
      expect(result[0].task.name, 'Bad Task');
      expect(result[0].roomName, 'Badezimmer');
      expect(result[0].roomId, room2Id);
      expect(result[1].task.name, 'Kueche Task');
      expect(result[1].roomName, 'Kueche');
      expect(result[1].roomId, room1Id);
    });
  });

  group('DailyPlanDao.watchCompletionsToday', () {
    test('returns 0 when no completions exist', () async {
      final count = await db.dailyPlanDao
          .watchCompletionsToday(today: DateTime(2026, 3, 16))
          .first;
      expect(count, 0);
    });

    test('returns correct count of completions recorded today', () async {
      final taskId = await db.tasksDao.insertTask(TasksCompanion.insert(
        roomId: room1Id,
        name: 'Abspuelen',
        intervalType: IntervalType.daily,
        effortLevel: EffortLevel.low,
        nextDueDate: DateTime(2026, 3, 16),
      ));

      // Complete the task (which records a completion at the given time)
      await db.tasksDao.completeTask(taskId, now: DateTime(2026, 3, 16, 10));

      // Create another task and complete it today too
      final taskId2 = await db.tasksDao.insertTask(TasksCompanion.insert(
        roomId: room1Id,
        name: 'Staubsaugen',
        intervalType: IntervalType.weekly,
        effortLevel: EffortLevel.medium,
        nextDueDate: DateTime(2026, 3, 16),
      ));
      await db.tasksDao.completeTask(taskId2, now: DateTime(2026, 3, 16, 14));

      final count = await db.dailyPlanDao
          .watchCompletionsToday(today: DateTime(2026, 3, 16))
          .first;
      expect(count, 2);
    });

    test('does not count completions from yesterday', () async {
      final taskId = await db.tasksDao.insertTask(TasksCompanion.insert(
        roomId: room1Id,
        name: 'Abspuelen',
        intervalType: IntervalType.daily,
        effortLevel: EffortLevel.low,
        nextDueDate: DateTime(2026, 3, 15),
      ));

      // Complete task yesterday
      await db.tasksDao.completeTask(taskId, now: DateTime(2026, 3, 15, 18));

      // Query for today (March 16) - should not include yesterday's completion
      final count = await db.dailyPlanDao
          .watchCompletionsToday(today: DateTime(2026, 3, 16))
          .first;
      expect(count, 0);
    });
  });
}
