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 roomId;

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

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

  group('TasksDao.watchCompletionsForTask', () {
    test('returns empty list when task has no completions', () async {
      final taskId = await db.tasksDao.insertTask(
        TasksCompanion.insert(
          roomId: roomId,
          name: 'Staubsaugen',
          intervalType: IntervalType.weekly,
          effortLevel: EffortLevel.medium,
          nextDueDate: DateTime(2026, 3, 15),
        ),
      );

      final completions =
          await db.tasksDao.watchCompletionsForTask(taskId).first;

      expect(completions, isEmpty);
    });

    test('returns completion after completeTask is called', () async {
      final taskId = await db.tasksDao.insertTask(
        TasksCompanion.insert(
          roomId: roomId,
          name: 'Abspuelen',
          intervalType: IntervalType.daily,
          effortLevel: EffortLevel.low,
          nextDueDate: DateTime(2026, 3, 15),
        ),
      );

      final completionTime = DateTime(2026, 3, 15, 10, 30);
      await db.tasksDao.completeTask(taskId, now: completionTime);

      final completions =
          await db.tasksDao.watchCompletionsForTask(taskId).first;

      expect(completions.length, 1);
      expect(completions.first.taskId, taskId);
      expect(completions.first.completedAt, completionTime);
    });

    test('returns multiple completions in reverse-chronological order', () async {
      final taskId = await db.tasksDao.insertTask(
        TasksCompanion.insert(
          roomId: roomId,
          name: 'Fenster putzen',
          intervalType: IntervalType.monthly,
          effortLevel: EffortLevel.high,
          nextDueDate: DateTime(2026, 1, 1),
        ),
      );

      // Complete multiple times with specific timestamps
      final time1 = DateTime(2026, 1, 10, 9, 0);
      final time2 = DateTime(2026, 2, 12, 14, 30);
      final time3 = DateTime(2026, 3, 15, 8, 0);

      // Insert out of order to verify ordering is enforced by query
      await db.tasksDao.completeTask(taskId, now: time1);
      await db.tasksDao.completeTask(taskId, now: time2);
      await db.tasksDao.completeTask(taskId, now: time3);

      final completions =
          await db.tasksDao.watchCompletionsForTask(taskId).first;

      expect(completions.length, 3);
      // Newest first (reverse-chronological)
      expect(completions[0].completedAt, time3);
      expect(completions[1].completedAt, time2);
      expect(completions[2].completedAt, time1);
    });

    test('completions for different tasks are isolated', () async {
      final taskId1 = await db.tasksDao.insertTask(
        TasksCompanion.insert(
          roomId: roomId,
          name: 'Task A',
          intervalType: IntervalType.daily,
          effortLevel: EffortLevel.low,
          nextDueDate: DateTime(2026, 3, 15),
        ),
      );

      final taskId2 = await db.tasksDao.insertTask(
        TasksCompanion.insert(
          roomId: roomId,
          name: 'Task B',
          intervalType: IntervalType.daily,
          effortLevel: EffortLevel.low,
          nextDueDate: DateTime(2026, 3, 15),
        ),
      );

      await db.tasksDao.completeTask(taskId1, now: DateTime(2026, 3, 15));

      final completionsForTask1 =
          await db.tasksDao.watchCompletionsForTask(taskId1).first;
      final completionsForTask2 =
          await db.tasksDao.watchCompletionsForTask(taskId2).first;

      expect(completionsForTask1.length, 1);
      expect(completionsForTask1.first.taskId, taskId1);
      expect(completionsForTask2, isEmpty);
    });

    test('stream emits updated list after new completion is added', () async {
      final taskId = await db.tasksDao.insertTask(
        TasksCompanion.insert(
          roomId: roomId,
          name: 'Bodenwischen',
          intervalType: IntervalType.weekly,
          effortLevel: EffortLevel.medium,
          nextDueDate: DateTime(2026, 3, 15),
        ),
      );

      // Collect stream emissions
      final emissions = <List<TaskCompletion>>[];
      final subscription = db.tasksDao
          .watchCompletionsForTask(taskId)
          .listen(emissions.add);

      // Wait for initial empty emission
      await Future<void>.delayed(const Duration(milliseconds: 50));
      expect(emissions.isNotEmpty, isTrue);
      expect(emissions.last, isEmpty);

      // Complete the task
      await db.tasksDao.completeTask(taskId, now: DateTime(2026, 3, 15, 9, 0));
      await Future<void>.delayed(const Duration(milliseconds: 50));

      expect(emissions.last.length, 1);

      await subscription.cancel();
    });
  });
}
