"""FRSME-INC020 perf — JudgeScore writes cache Application.computed_score."""
from __future__ import annotations

from decimal import Decimal

import pytest
from django.contrib.auth import get_user_model

from apps.core.permissions.roles import UserRole
from apps.smehub.incubation.models import (
    Application,
    JudgeScore,
    Programme,
    RubricSection,
    ScoringRubric,
)
from apps.smehub.onboarding.models import Business, BusinessStage, EntrepreneurProfile

User = get_user_model()
pytestmark = pytest.mark.django_db


@pytest.fixture
def admin():
    return User.objects.create_user(
        email="adm-sc@example.com", password="x",
        is_superuser=True, is_staff=True, role=UserRole.SYSTEM_ADMIN,
    )


@pytest.fixture
def entrepreneur(admin):
    user = User.objects.create_user(email="ent-sc@example.com", password="x", role=UserRole.ENTREPRENEUR)
    profile = EntrepreneurProfile.objects.create(user=user, country="UG", organisation="Co")
    profile.verify(by_user=admin)
    profile.save()
    return profile


@pytest.fixture
def verified_business(entrepreneur, admin):
    biz = Business.objects.create(
        entrepreneur=entrepreneur,
        name="Score Cache Biz",
        sector="Agriculture",
        business_stage=BusinessStage.MVP,
        country="UG",
    )
    biz.verify(by_user=admin)
    biz.save()
    return biz


@pytest.fixture
def programme_with_rubric():
    prog = Programme.objects.create(
        title="SC Programme",
        slug="sc-prog",
        cohort_size=10,
        duration_weeks=12,
    )
    rubric = ScoringRubric.objects.create(programme=prog)
    RubricSection.objects.create(
        rubric=rubric, title="Innovation", weight=Decimal("0.5"), max_marks=10, order=1,
    )
    RubricSection.objects.create(
        rubric=rubric, title="Impact", weight=Decimal("0.5"), max_marks=10, order=2,
    )
    return prog


@pytest.fixture
def application(programme_with_rubric, entrepreneur, verified_business):
    return Application.objects.create(
        programme=programme_with_rubric,
        entrepreneur=entrepreneur,
        business=verified_business,
    )


@pytest.fixture
def judge():
    return User.objects.create_user(email="jud-sc@example.com", password="x", role=UserRole.JUDGE)


def test_judgescore_post_save_caches_computed_score(application, judge):
    """Saving a JudgeScore triggers compute_weighted_average via signal."""
    sections = list(application.programme.rubric.sections.all())
    # Initial state: no scores → computed_score is None.
    assert application.computed_score is None

    JudgeScore.objects.create(
        application=application,
        judge=judge,
        section=sections[0],
        score=Decimal("8"),
    )
    refreshed = Application.objects.get(pk=application.pk)
    # Only section 0 has scores; section 1 contributes 0. 8/10 * 0.5 * 100 = 40.
    assert refreshed.computed_score == Decimal("40.00")

    JudgeScore.objects.create(
        application=application,
        judge=judge,
        section=sections[1],
        score=Decimal("6"),
    )
    refreshed = Application.objects.get(pk=application.pk)
    # Both sections: 8/10 * 0.5 * 100 + 6/10 * 0.5 * 100 = 70.
    assert refreshed.computed_score == Decimal("70.00")


def test_judgescore_delete_recomputes_score(application, judge):
    sections = list(application.programme.rubric.sections.all())
    js = JudgeScore.objects.create(
        application=application,
        judge=judge,
        section=sections[0],
        score=Decimal("10"),
    )
    refreshed = Application.objects.get(pk=application.pk)
    assert refreshed.computed_score == Decimal("50.00")

    js.delete()
    refreshed = Application.objects.get(pk=application.pk)
    assert refreshed.computed_score == Decimal("0.00")
