"""EligibilityRuleForm — the 8 rule types added to close the FRFA-CS012/013
gap (SRS: base eligibility criteria — sector/thematic area, age, required
documentation checklist — plus type-specific criteria for scholarship,
fellowship, and challenge calls). Mirrors the serialization/hydration
contract style of test_eligibility_rule_form.py for the original 3 types.
"""
from datetime import timedelta

import pytest
from django.utils import timezone

from apps.core.authentication.models import Institution
from apps.rims.grants.forms import EligibilityRuleForm
from apps.rims.grants.models import EligibilityRule, GrantCall


@pytest.fixture
def call(db):
    return GrantCall.objects.create(
        title="Extended eligibility form test call",
        slug="eligibility-form-test-call-ext",
        opens_at=timezone.now() - timedelta(days=1),
        closes_at=timezone.now() + timedelta(days=30),
        status=GrantCall.Status.DRAFT,
    )


@pytest.fixture
def institutions(db):
    return [
        Institution.objects.create(name="Ext Uni A", country="Uganda", is_member=True),
        Institution.objects.create(name="Ext Uni B", country="Kenya", is_member=True),
    ]


def _post(rule_type, **extra):
    return {"rule_type": rule_type, "is_blocking": "on", **extra}


# ── Serialization ──────────────────────────────────────────────────────────

def test_sector_field_serializes_to_tags_key(call):
    form = EligibilityRuleForm(
        data=_post("sector", sector_tags="agritech, climate"),
        instance=EligibilityRule(call=call),
    )
    assert form.is_valid(), form.errors
    rule = form.save(commit=False)
    rule.call = call
    rule.save()
    assert rule.params == {"tags": ["agritech", "climate"]}


def test_age_field_serializes_to_min_max_keys(call):
    form = EligibilityRuleForm(
        data=_post("age", age_min="18", age_max="35"),
        instance=EligibilityRule(call=call),
    )
    assert form.is_valid(), form.errors
    rule = form.save(commit=False)
    rule.call = call
    rule.save()
    assert rule.params == {"min_age": 18, "max_age": 35}


def test_documentation_field_serializes_to_required_labels_key(call):
    form = EligibilityRuleForm(
        data=_post("documentation", documentation_labels="CV, Reference letter"),
        instance=EligibilityRule(call=call),
    )
    assert form.is_valid(), form.errors
    rule = form.save(commit=False)
    rule.call = call
    rule.save()
    assert rule.params == {"required_labels": ["CV", "Reference letter"]}


def test_scholarship_university_field_serializes_to_institution_ids_key(call, institutions):
    inst_a, inst_b = institutions
    form = EligibilityRuleForm(
        data=_post("scholarship_university", scholarship_university_ids=[inst_a.pk, inst_b.pk]),
        instance=EligibilityRule(call=call),
    )
    assert form.is_valid(), form.errors
    rule = form.save(commit=False)
    rule.call = call
    rule.save()
    assert rule.params == {"institution_ids": [inst_a.pk, inst_b.pk]}


def test_scholarship_course_field_serializes_to_keywords_key(call):
    form = EligibilityRuleForm(
        data=_post("scholarship_course", scholarship_course_keywords="agriculture, economics"),
        instance=EligibilityRule(call=call),
    )
    assert form.is_valid(), form.errors
    rule = form.save(commit=False)
    rule.call = call
    rule.save()
    assert rule.params == {"keywords": ["agriculture", "economics"]}


def test_fellowship_host_institution_field_serializes_to_institutions_key(call):
    form = EligibilityRuleForm(
        data=_post("fellowship_host_institution", fellowship_host_institutions="Makerere University"),
        instance=EligibilityRule(call=call),
    )
    assert form.is_valid(), form.errors
    rule = form.save(commit=False)
    rule.call = call
    rule.save()
    assert rule.params == {"institutions": ["Makerere University"]}


def test_fellowship_type_field_serializes_to_types_key(call):
    form = EligibilityRuleForm(
        data=_post("fellowship_type", fellowship_types=["lectures", "supervision"]),
        instance=EligibilityRule(call=call),
    )
    assert form.is_valid(), form.errors
    rule = form.save(commit=False)
    rule.call = call
    rule.save()
    assert rule.params == {"types": ["lectures", "supervision"]}


def test_challenge_innovation_stage_field_serializes_to_stages_key(call):
    form = EligibilityRuleForm(
        data=_post("challenge_innovation_stage", challenge_innovation_stages=["prototype", "pilot"]),
        instance=EligibilityRule(call=call),
    )
    assert form.is_valid(), form.errors
    rule = form.save(commit=False)
    rule.call = call
    rule.save()
    assert rule.params == {"stages": ["prototype", "pilot"]}


# ── Hydration ───────────────────────────────────────────────────────────────

def test_existing_sector_rule_hydrates_tags_initial(call):
    rule = EligibilityRule.objects.create(
        call=call, rule_type="sector", params={"tags": ["agritech", "climate"]}, is_blocking=True
    )
    form = EligibilityRuleForm(instance=rule)
    assert form.fields["sector_tags"].initial == "agritech, climate"


def test_existing_age_rule_hydrates_min_max_initial(call):
    rule = EligibilityRule.objects.create(
        call=call, rule_type="age", params={"min_age": 18, "max_age": 35}, is_blocking=True
    )
    form = EligibilityRuleForm(instance=rule)
    assert form.fields["age_min"].initial == 18
    assert form.fields["age_max"].initial == 35


def test_existing_challenge_stage_rule_hydrates_stages_initial(call):
    rule = EligibilityRule.objects.create(
        call=call, rule_type="challenge_innovation_stage", params={"stages": ["pilot"]}, is_blocking=True
    )
    form = EligibilityRuleForm(instance=rule)
    assert form.fields["challenge_innovation_stages"].initial == ["pilot"]
