"""The organization backfill migration must keep every pre-existing row and never create noise."""
import datetime

from django.db import connection
from django.db.migrations.executor import MigrationExecutor
from django.test import TransactionTestCase

BEFORE = [("infrastructure", "0003_user_mobile_user_mobile_verified_at_user_username")]
AFTER = [("infrastructure", "0005_attendance_organization_required")]


class OrganizationBackfillMigrationTests(TransactionTestCase):
    def migrate(self, targets):
        executor = MigrationExecutor(connection)
        executor.loader.build_graph()
        executor.migrate(targets)
        return MigrationExecutor(connection).loader.project_state(targets).apps

    def tearDown(self):
        self.migrate(AFTER)  # leave the schema fully migrated for any test that follows

    def test_existing_rows_are_moved_into_the_default_organization(self):
        old = self.migrate(BEFORE)
        User, Attendance = old.get_model("infrastructure", "User"), old.get_model("infrastructure", "Attendance")
        Holiday, WorkSchedule = old.get_model("infrastructure", "Holiday"), old.get_model("infrastructure", "WorkSchedule")
        Leave = old.get_model("infrastructure", "LeaveRequest")
        user = User.objects.create(personnel_code="m1", password="x")
        today = datetime.date(2026, 10, 1)
        Attendance.objects.create(user=user, date=today, check_in=datetime.time(8, 0))
        Attendance.objects.create(user=user, date=today + datetime.timedelta(days=1))
        Holiday.objects.create(date=today, title="H")
        WorkSchedule.objects.create(date=None, standard_check_in=datetime.time(8, 0), standard_check_out=datetime.time(16, 0))
        Leave.objects.create(user=user, date=today, type="daily", category="annual")

        new = self.migrate(AFTER)
        Organization = new.get_model("organizations", "Organization")
        organization = Organization.objects.get(slug="default")
        self.assertEqual(Organization.objects.count(), 1)
        self.assertEqual(organization.kind, "customer")
        for name, expected in (("Attendance", 2), ("Holiday", 1), ("WorkSchedule", 1), ("LeaveRequest", 1)):
            model = new.get_model("infrastructure", name)
            self.assertEqual(model.objects.count(), expected, name)
            self.assertEqual(model.objects.filter(organization=organization).count(), expected, name)

    def test_empty_database_gets_no_stray_organization(self):
        self.migrate(BEFORE)
        new = self.migrate(AFTER)
        self.assertEqual(new.get_model("organizations", "Organization").objects.count(), 0)

    def test_migration_can_be_reversed_without_losing_rows(self):
        old = self.migrate(BEFORE)
        User, Attendance = old.get_model("infrastructure", "User"), old.get_model("infrastructure", "Attendance")
        user = User.objects.create(personnel_code="m2", password="x")
        Attendance.objects.create(user=user, date=datetime.date(2026, 10, 2))
        self.migrate(AFTER)
        back = self.migrate(BEFORE)
        self.assertEqual(back.get_model("infrastructure", "Attendance").objects.count(), 1)
