"""Phase 8 — MoU two-party confirmation UI (FRSME-MPL013).

The service ``confirm_mou_party`` shipped in Phase 6/7 audit closure but no
view ever called it, leaving production unable to formalise MoUs. These
tests cover the new ``MoUConfirmPartyView`` + workspace template gating.
"""
from __future__ import annotations

import pytest
from django.contrib.auth import get_user_model
from django.urls import reverse

from apps.core.permissions.roles import UserRole
from apps.smehub.linkage import services
from apps.smehub.linkage.models import (
    MoU,
    MoUPartyConfirmation,
    PartnerDirectoryEntry,
)
from apps.smehub.onboarding.models import EntrepreneurProfile

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


# ---------------------------------------------------------------------------
# Fixtures
# ---------------------------------------------------------------------------

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


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


@pytest.fixture
def partner_user():
    return User.objects.create_user(
        email="partner-mou8@example.com", password="x", role=UserRole.PARTNER,
    )


@pytest.fixture
def verified_partner(admin, partner_user):
    entry = PartnerDirectoryEntry.objects.create(
        organisation_name="MoU8 Partner",
        org_type=PartnerDirectoryEntry.OrgType.NGO,
        managed_by=partner_user,
    )
    entry.verify(by_user=admin)
    entry.save()
    return entry


@pytest.fixture
def outsider():
    return User.objects.create_user(
        email="other-mou8@example.com", password="x", role=UserRole.ENTREPRENEUR,
    )


@pytest.fixture
def draft_mou(entrepreneur, verified_partner, partner_user):
    cr = services.request_connection(entrepreneur=entrepreneur, target=verified_partner)
    connection = services.accept_connection(cr, by_user=partner_user)
    return services.init_mou(connection=connection, title="MoU8 Draft", by_user=entrepreneur.user)


def _confirm_url(mou: MoU, party: str) -> str:
    return reverse("smehub_linkage:mou_confirm_party", kwargs={"pk": mou.pk, "party": party})


def _workspace_url(mou: MoU) -> str:
    return reverse("smehub_linkage:mou_workspace", kwargs={"pk": mou.pk})


# ---------------------------------------------------------------------------
# Confirm-party view
# ---------------------------------------------------------------------------

def test_entrepreneur_can_confirm_via_view(client, draft_mou, entrepreneur):
    client.force_login(entrepreneur.user)
    resp = client.post(_confirm_url(draft_mou, "entrepreneur"))
    assert resp.status_code == 302
    assert MoUPartyConfirmation.objects.filter(
        mou=draft_mou, party="entrepreneur",
    ).exists()


def test_counterparty_can_confirm_via_view(client, draft_mou, partner_user):
    client.force_login(partner_user)
    resp = client.post(_confirm_url(draft_mou, "counterparty"))
    assert resp.status_code == 302
    assert MoUPartyConfirmation.objects.filter(
        mou=draft_mou, party="counterparty",
    ).exists()


def test_admin_can_confirm_either_party(client, draft_mou, admin):
    client.force_login(admin)
    client.post(_confirm_url(draft_mou, "entrepreneur"))
    client.post(_confirm_url(draft_mou, "counterparty"))
    assert MoUPartyConfirmation.objects.filter(mou=draft_mou).count() == 2


def test_other_user_cannot_confirm_as_entrepreneur(client, draft_mou, outsider):
    client.force_login(outsider)
    resp = client.post(_confirm_url(draft_mou, "entrepreneur"))
    assert resp.status_code == 403
    assert not MoUPartyConfirmation.objects.filter(mou=draft_mou).exists()


def test_partner_cannot_confirm_as_entrepreneur(client, draft_mou, partner_user):
    """Counterparty owner trying to slip in as entrepreneur is denied."""
    client.force_login(partner_user)
    resp = client.post(_confirm_url(draft_mou, "entrepreneur"))
    assert resp.status_code == 403


def test_entrepreneur_cannot_confirm_as_counterparty(client, draft_mou, entrepreneur):
    client.force_login(entrepreneur.user)
    resp = client.post(_confirm_url(draft_mou, "counterparty"))
    assert resp.status_code == 403


def test_unknown_party_token_returns_404(client, draft_mou, admin):
    client.force_login(admin)
    resp = client.post(_confirm_url(draft_mou, "bogus"))
    assert resp.status_code == 404


def test_confirm_is_idempotent_via_view(client, draft_mou, entrepreneur):
    client.force_login(entrepreneur.user)
    client.post(_confirm_url(draft_mou, "entrepreneur"))
    client.post(_confirm_url(draft_mou, "entrepreneur"))
    assert MoUPartyConfirmation.objects.filter(
        mou=draft_mou, party="entrepreneur",
    ).count() == 1


# ---------------------------------------------------------------------------
# Workspace template gating
# ---------------------------------------------------------------------------

def test_workspace_hides_formalise_until_both_confirm(client, draft_mou, entrepreneur):
    client.force_login(entrepreneur.user)
    resp = client.get(_workspace_url(draft_mou))
    assert resp.status_code == 200
    assert b"Step 2 locked" in resp.content
    assert b"Upload &amp; formalise" not in resp.content


def test_workspace_shows_formalise_after_both_confirm(
    client, draft_mou, entrepreneur, partner_user,
):
    services.confirm_mou_party(draft_mou, party="entrepreneur", by_user=entrepreneur.user)
    services.confirm_mou_party(draft_mou, party="counterparty", by_user=partner_user)
    client.force_login(entrepreneur.user)
    resp = client.get(_workspace_url(draft_mou))
    assert resp.status_code == 200
    assert b"Step 2 locked" not in resp.content
    assert b"Upload &amp; formalise" in resp.content


def test_workspace_shows_confirm_button_for_entrepreneur(client, draft_mou, entrepreneur):
    client.force_login(entrepreneur.user)
    resp = client.get(_workspace_url(draft_mou))
    assert b"Confirm as entrepreneur" in resp.content


def test_workspace_hides_confirm_button_after_self_confirm(
    client, draft_mou, entrepreneur,
):
    services.confirm_mou_party(draft_mou, party="entrepreneur", by_user=entrepreneur.user)
    client.force_login(entrepreneur.user)
    resp = client.get(_workspace_url(draft_mou))
    assert b"Confirm as entrepreneur" not in resp.content
    assert b"Entrepreneur confirmed" in resp.content


def test_workspace_shows_counterparty_button_for_partner(client, draft_mou, partner_user):
    client.force_login(partner_user)
    resp = client.get(_workspace_url(draft_mou))
    assert b"Confirm as counterparty" in resp.content
