import 'package:drift/native.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:drift/drift.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;

  setUp(() {
    db = AppDatabase(NativeDatabase.memory());
  });

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

  group('RoomsDao', () {
    test('insertRoom returns a valid id', () async {
      final id = await db.roomsDao.insertRoom(
        RoomsCompanion.insert(name: 'Kueche', iconName: 'kitchen'),
      );
      expect(id, greaterThan(0));
    });

    test('watchAllRooms emits rooms ordered by sortOrder', () async {
      // Insert rooms with different sort orders
      await db.roomsDao.insertRoom(
        RoomsCompanion.insert(
          name: 'Badezimmer',
          iconName: 'bathtub',
          sortOrder: Value(2),
        ),
      );
      await db.roomsDao.insertRoom(
        RoomsCompanion.insert(
          name: 'Kueche',
          iconName: 'kitchen',
          sortOrder: Value(0),
        ),
      );
      await db.roomsDao.insertRoom(
        RoomsCompanion.insert(
          name: 'Schlafzimmer',
          iconName: 'bed',
          sortOrder: Value(1),
        ),
      );

      final rooms = await db.roomsDao.watchAllRooms().first;

      expect(rooms.length, 3);
      expect(rooms[0].name, 'Kueche');
      expect(rooms[1].name, 'Schlafzimmer');
      expect(rooms[2].name, 'Badezimmer');
    });

    test('updateRoom changes name and iconName', () async {
      final id = await db.roomsDao.insertRoom(
        RoomsCompanion.insert(name: 'Kueche', iconName: 'kitchen'),
      );

      final room = await db.roomsDao.getRoomById(id);
      final updated = room.copyWith(name: 'Wohnkueche', iconName: 'dining');
      await db.roomsDao.updateRoom(updated);

      final result = await db.roomsDao.getRoomById(id);
      expect(result.name, 'Wohnkueche');
      expect(result.iconName, 'dining');
    });

    test('deleteRoom cascades to associated tasks and completions', () async {
      // Create room
      final roomId = await db.roomsDao.insertRoom(
        RoomsCompanion.insert(name: 'Kueche', iconName: 'kitchen'),
      );

      // Create task in the room
      final taskId = await db.tasksDao.insertTask(
        TasksCompanion.insert(
          roomId: roomId,
          name: 'Abspuelen',
          intervalType: IntervalType.daily,
          effortLevel: EffortLevel.low,
          nextDueDate: DateTime(2026, 3, 15),
        ),
      );

      // Complete the task to create a completion record
      await db.tasksDao.completeTask(taskId, now: DateTime(2026, 3, 15));

      // Verify task and completion exist
      final tasksBefore = await db.tasksDao.watchTasksInRoom(roomId).first;
      expect(tasksBefore.length, 1);

      // Delete room
      await db.roomsDao.deleteRoom(roomId);

      // Verify room is gone
      final rooms = await db.roomsDao.watchAllRooms().first;
      expect(rooms, isEmpty);

      // Verify tasks are gone
      final tasksAfter = await db.tasksDao.watchTasksInRoom(roomId).first;
      expect(tasksAfter, isEmpty);
    });

    test('reorderRooms updates sortOrder for all rooms', () async {
      final id1 = await db.roomsDao.insertRoom(
        RoomsCompanion.insert(name: 'Kueche', iconName: 'kitchen'),
      );
      final id2 = await db.roomsDao.insertRoom(
        RoomsCompanion.insert(name: 'Bad', iconName: 'bathtub'),
      );
      final id3 = await db.roomsDao.insertRoom(
        RoomsCompanion.insert(name: 'Schlafzimmer', iconName: 'bed'),
      );

      // Reorder: Bad first, then Schlafzimmer, then Kueche
      await db.roomsDao.reorderRooms([id2, id3, id1]);

      final rooms = await db.roomsDao.watchAllRooms().first;
      expect(rooms[0].name, 'Bad');
      expect(rooms[1].name, 'Schlafzimmer');
      expect(rooms[2].name, 'Kueche');
    });

    test('watchRoomWithStats emits room with due task count and cleanliness ratio', () async {
      final roomId = await db.roomsDao.insertRoom(
        RoomsCompanion.insert(name: 'Kueche', iconName: 'kitchen'),
      );

      final today = DateTime(2026, 3, 15);

      // Add a task due today (counts as "due")
      await db.tasksDao.insertTask(
        TasksCompanion.insert(
          roomId: roomId,
          name: 'Task Due Today',
          intervalType: IntervalType.daily,
          effortLevel: EffortLevel.low,
          nextDueDate: today,
        ),
      );

      // Add an overdue task (yesterday)
      await db.tasksDao.insertTask(
        TasksCompanion.insert(
          roomId: roomId,
          name: 'Overdue Task',
          intervalType: IntervalType.weekly,
          effortLevel: EffortLevel.medium,
          nextDueDate: DateTime(2026, 3, 14),
        ),
      );

      // Add a future task
      await db.tasksDao.insertTask(
        TasksCompanion.insert(
          roomId: roomId,
          name: 'Future Task',
          intervalType: IntervalType.monthly,
          effortLevel: EffortLevel.low,
          nextDueDate: DateTime(2026, 3, 20),
        ),
      );

      final stats = await db.roomsDao.watchRoomWithStats(today: today).first;

      expect(stats.length, 1);
      final roomStats = stats.first;
      expect(roomStats.room.name, 'Kueche');
      expect(roomStats.totalTasks, 3);
      // "Due" means on or before today: today (Mar 15) + overdue (Mar 14) = 2
      expect(roomStats.dueTasks, 2);
      // "Overdue" means strictly before today: Mar 14 = 1
      expect(roomStats.overdueCount, 1);
      // Cleanliness: (3 - 1) / 3 = 0.6667
      expect(roomStats.cleanlinessRatio, closeTo(0.6667, 0.001));
    });
  });
}
