"""Slice B.3e · MoUAmendView role matrix (PRD A5).

Asserts that ``MoUAmendView`` accepts a POST from:
* the entrepreneur who owns the MoU's connection;
* the counterparty (directory entry's ``managed_by`` user);
* an SME admin;

and rejects unrelated users with 403.
"""
from __future__ import annotations

from io import BytesIO

import pytest
from django.contrib.auth import get_user_model
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import Client
from django.urls import reverse

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

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


@pytest.fixture
def admin():
    return User.objects.create_user(
        email="adm-mou@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-mou@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 partner_user():
    return User.objects.create_user(email="partner-mou@example.com", password="x", role=UserRole.PARTNER)


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


@pytest.fixture
def mou(entrepreneur, partner, admin):
    cr = services.request_connection(entrepreneur=entrepreneur, target=partner, message="Hi")
    services.accept_connection(cr, by_user=admin)
    connection = Connection.objects.get(request=cr)
    return MoU.objects.create(
        connection=connection,
        title="Initial MoU",
        created_by=entrepreneur.user,
    )


def _pdf_upload() -> SimpleUploadedFile:
    return SimpleUploadedFile(
        "draft.pdf",
        b"%PDF-1.4\n%fake\n%%EOF\n",
        content_type="application/pdf",
    )


def _form_data() -> dict:
    return {
        "title": "Amended MoU v2",
        "summary": "Scope expanded.",
    }


def test_entrepreneur_can_amend(mou, entrepreneur):
    client = Client()
    client.force_login(entrepreneur.user)
    url = reverse("smehub_linkage:mou_amend", kwargs={"pk": mou.pk})
    data = {**_form_data(), "draft_file": _pdf_upload()}
    resp = client.post(url, data)
    assert resp.status_code in (302, 200)  # success or form-render — both indicate no 403


def test_counterparty_can_amend(mou, partner_user):
    client = Client()
    client.force_login(partner_user)
    url = reverse("smehub_linkage:mou_amend", kwargs={"pk": mou.pk})
    data = {**_form_data(), "draft_file": _pdf_upload()}
    resp = client.post(url, data)
    assert resp.status_code in (302, 200)


def test_admin_can_amend(mou, admin):
    client = Client()
    client.force_login(admin)
    url = reverse("smehub_linkage:mou_amend", kwargs={"pk": mou.pk})
    data = {**_form_data(), "draft_file": _pdf_upload()}
    resp = client.post(url, data)
    assert resp.status_code in (302, 200)


def test_unrelated_user_blocked(mou):
    other = User.objects.create_user(email="other-mou@example.com", password="x", role=UserRole.JUDGE)
    client = Client()
    client.force_login(other)
    url = reverse("smehub_linkage:mou_amend", kwargs={"pk": mou.pk})
    data = {**_form_data(), "draft_file": _pdf_upload()}
    resp = client.post(url, data)
    assert resp.status_code == 403
