"""Add TenantScopedModel fields to leave/attendance models.

Adds organization_node FK to all leave/attendance models and tenant FK
to models that don't already have it (LeaveBalance, EmployeeShift).

Fields are added nullable first, populated from employee records, then
altered to non-nullable where appropriate.
"""

from django.db import migrations, models


def populate_tenant_and_org_node(apps, schema_editor):
    """Backfill tenant_id and organization_node_id from parent employee."""
    Employee = apps.get_model("hr_core", "Employee")
    LeaveBalance = apps.get_model("hr_core", "LeaveBalance")
    LeaveRequest = apps.get_model("hr_core", "LeaveRequest")
    EmployeeShift = apps.get_model("hr_core", "EmployeeShift")
    AttendanceRecord = apps.get_model("hr_core", "AttendanceRecord")

    # LeaveBalance: populate tenant + org_node from employee
    for balance in LeaveBalance.objects.filter(tenant__isnull=True).select_related("employee"):
        balance.tenant_id = balance.employee.tenant_id
        balance.organization_node_id = balance.employee.organization_node_id
        balance.save(update_fields=["tenant_id", "organization_node_id"])

    # LeaveRequest: populate org_node from employee
    for req in LeaveRequest.objects.filter(organization_node__isnull=True).select_related("employee"):
        req.organization_node_id = req.employee.organization_node_id
        req.save(update_fields=["organization_node_id"])

    # EmployeeShift: populate tenant + org_node from employee
    for es in EmployeeShift.objects.filter(tenant__isnull=True).select_related("employee"):
        es.tenant_id = es.employee.tenant_id
        es.organization_node_id = es.employee.organization_node_id
        es.save(update_fields=["tenant_id", "organization_node_id"])

    # AttendanceRecord: populate org_node from employee
    for record in AttendanceRecord.objects.filter(organization_node__isnull=True).select_related("employee"):
        record.organization_node_id = record.employee.organization_node_id
        record.save(update_fields=["organization_node_id"])


def noop(apps, schema_editor):
    pass


class Migration(migrations.Migration):

    dependencies = [
        ("tenants", "0001_initial"),
        ("organizations", "0002_workspace_template_user_context_pref"),
        ("hr_core", "0001_initial"),
    ]

    operations = [
        # ── 1. Add organization_node to reference-data models (nullable, stays nullable) ──

        migrations.AddField(
            model_name="leavetype",
            name="organization_node",
            field=models.ForeignKey(
                blank=True, null=True,
                on_delete=models.deletion.SET_NULL, related_name="+",
                to="organizations.organizationnode", verbose_name="organization node",
            ),
        ),
        migrations.AddField(
            model_name="publicholiday",
            name="organization_node",
            field=models.ForeignKey(
                blank=True, null=True,
                on_delete=models.deletion.SET_NULL, related_name="+",
                to="organizations.organizationnode", verbose_name="organization node",
            ),
        ),
        migrations.AddField(
            model_name="shiftdefinition",
            name="organization_node",
            field=models.ForeignKey(
                blank=True, null=True,
                on_delete=models.deletion.SET_NULL, related_name="+",
                to="organizations.organizationnode", verbose_name="organization node",
            ),
        ),

        # ── 2. Add tenant + org_node (nullable) to models that need them populated ──

        migrations.AddField(
            model_name="leavebalance",
            name="tenant",
            field=models.ForeignKey(
                null=True, on_delete=models.deletion.CASCADE, related_name="+",
                to="tenants.tenant", verbose_name="tenant",
            ),
        ),
        migrations.AddField(
            model_name="leavebalance",
            name="organization_node",
            field=models.ForeignKey(
                null=True, on_delete=models.deletion.PROTECT, related_name="+",
                to="organizations.organizationnode", verbose_name="organization node",
            ),
        ),

        migrations.AddField(
            model_name="leaverequest",
            name="organization_node",
            field=models.ForeignKey(
                null=True, on_delete=models.deletion.PROTECT, related_name="+",
                to="organizations.organizationnode", verbose_name="organization node",
            ),
        ),

        migrations.AddField(
            model_name="employeeshift",
            name="tenant",
            field=models.ForeignKey(
                null=True, on_delete=models.deletion.CASCADE, related_name="+",
                to="tenants.tenant", verbose_name="tenant",
            ),
        ),
        migrations.AddField(
            model_name="employeeshift",
            name="organization_node",
            field=models.ForeignKey(
                null=True, on_delete=models.deletion.PROTECT, related_name="+",
                to="organizations.organizationnode", verbose_name="organization node",
            ),
        ),

        migrations.AddField(
            model_name="attendancerecord",
            name="organization_node",
            field=models.ForeignKey(
                null=True, on_delete=models.deletion.PROTECT, related_name="+",
                to="organizations.organizationnode", verbose_name="organization node",
            ),
        ),

        # ── 3. Data migration: populate from parent employee ──

        migrations.RunPython(populate_tenant_and_org_node, reverse_code=noop),

        # ── 4. Alter to non-nullable where appropriate ──

        migrations.AlterField(
            model_name="leavebalance",
            name="tenant",
            field=models.ForeignKey(
                on_delete=models.deletion.CASCADE, related_name="+",
                to="tenants.tenant", verbose_name="tenant",
            ),
        ),
        migrations.AlterField(
            model_name="leavebalance",
            name="organization_node",
            field=models.ForeignKey(
                on_delete=models.deletion.PROTECT, related_name="+",
                to="organizations.organizationnode", verbose_name="organization node",
            ),
        ),
        migrations.AlterField(
            model_name="leaverequest",
            name="organization_node",
            field=models.ForeignKey(
                on_delete=models.deletion.PROTECT, related_name="+",
                to="organizations.organizationnode", verbose_name="organization node",
            ),
        ),
        migrations.AlterField(
            model_name="employeeshift",
            name="tenant",
            field=models.ForeignKey(
                on_delete=models.deletion.CASCADE, related_name="+",
                to="tenants.tenant", verbose_name="tenant",
            ),
        ),
        migrations.AlterField(
            model_name="employeeshift",
            name="organization_node",
            field=models.ForeignKey(
                on_delete=models.deletion.PROTECT, related_name="+",
                to="organizations.organizationnode", verbose_name="organization node",
            ),
        ),
        migrations.AlterField(
            model_name="attendancerecord",
            name="organization_node",
            field=models.ForeignKey(
                on_delete=models.deletion.PROTECT, related_name="+",
                to="organizations.organizationnode", verbose_name="organization node",
            ),
        ),
    ]
