"""BE-002: writable cross-org FKs across projects serializers must be
rejected, not merely existence-checked. Mirrors the pattern already applied
to apps.hr / apps.finance / apps.accounting / apps.meetings / apps.events /
apps.asset_management."""
from datetime import date

import pytest
from rest_framework.test import APIClient

from apps.companies.models import Company, Organization, OrganizationMembership
from apps.core.models import User
from apps.projects.models import Project, ProjectFund, CashAdvance


def api(user):
    client = APIClient()
    client.force_authenticate(user)
    return client


@pytest.fixture
def org_a(db):
    return Organization.objects.create(name="Org A")


@pytest.fixture
def org_b(db):
    return Organization.objects.create(name="Org B")


@pytest.fixture
def director_a(org_a):
    user = User.objects.create_user(email="director-a@projects.test", password="p", organization_role="director")
    OrganizationMembership.objects.create(organization=org_a, user=user)
    return user


@pytest.fixture
def project_a(org_a):
    return Project.objects.create(organization=org_a, name="Org A Project")


@pytest.fixture
def project_b(org_b):
    return Project.objects.create(organization=org_b, name="Org B Project")


@pytest.mark.django_db
class TestProjectCrossTenantWrite:
    def test_create_rejects_cross_org_lead(self, director_a, org_a, org_b):
        from apps.hr.signals import ensure_employee_stub
        from apps.hr.models import Employee

        other = User.objects.create_user(email="lead-b@projects.test", password="p")
        OrganizationMembership.objects.create(organization=org_b, user=other)
        ensure_employee_stub(other)
        lead_b = Employee.objects.get(user=other)
        client = api(director_a)
        resp = client.post("/api/projects/", {"name": "New Project", "lead": str(lead_b.id)}, format="json")
        assert resp.status_code == 400
        assert resp.data["lead"][0].code == "does_not_exist"


@pytest.mark.django_db
class TestProjectTeamMemberCrossTenantWrite:
    def test_create_rejects_cross_org_project(self, director_a, org_a, project_b):
        client = api(director_a)
        resp = client.post("/api/project-team-members/", {
            "project": str(project_b.id), "user": str(director_a.id),
        }, format="json")
        assert resp.status_code == 400
        assert resp.data["project"][0].code == "does_not_exist"


@pytest.mark.django_db
class TestProjectFundCrossTenantWrite:
    def test_create_rejects_cross_org_donor(self, director_a, org_a, org_b, project_a):
        donor_b = Company.objects.create(organization=org_b, name="Org B Donor")
        client = api(director_a)
        resp = client.post("/api/project-funds/", {
            "project": str(project_a.id), "donor": str(donor_b.id),
            "source": "Org B Donor", "amount": "1000.00", "currency": "USD",
        }, format="json")
        assert resp.status_code == 403
        assert not ProjectFund.objects.filter(donor=donor_b).exists()

    def test_create_rejects_cross_org_project(self, director_a, org_a, project_b):
        client = api(director_a)
        resp = client.post("/api/project-funds/", {
            "project": str(project_b.id), "source": "Direct", "amount": "1000.00", "currency": "USD",
        }, format="json")
        assert resp.status_code == 403
        assert not ProjectFund.objects.filter(project=project_b).exists()


@pytest.mark.django_db
class TestCashAdvanceCrossTenantWrite:
    def test_create_rejects_cross_org_fund(self, director_a, org_a, org_b, project_a):
        from apps.hr.signals import ensure_employee_stub
        from apps.hr.models import Employee

        ensure_employee_stub(director_a)
        recipient_a = Employee.objects.get(user=director_a)
        fund_b = ProjectFund.objects.create(
            organization=org_b, source="Org B Fund", amount="1000.00", currency="USD",
        )
        client = api(director_a)
        resp = client.post("/api/cash-advances/", {
            "project": str(project_a.id), "fund": str(fund_b.id), "recipient": str(recipient_a.id),
            "purpose": "Probe", "amount": "100.00", "currency": "USD",
            "date_issued": date.today().isoformat(),
        }, format="json")
        assert resp.status_code == 403
        assert not CashAdvance.objects.filter(fund=fund_b).exists()


@pytest.mark.django_db
class TestFundingOpportunityCrossTenantWrite:
    def test_create_rejects_cross_org_fund(self, director_a, org_a, org_b):
        fund_b = ProjectFund.objects.create(
            organization=org_b, source="Org B Fund", amount="1000.00", currency="USD",
        )
        client = api(director_a)
        resp = client.post("/api/funding-opportunities/", {
            "fund": str(fund_b.id), "name": "Probe Opportunity",
        }, format="json")
        assert resp.status_code == 403
        assert not fund_b.opportunities.exists()


@pytest.mark.django_db
class TestPaymentRequestFormCrossTenantWrite:
    def test_create_rejects_cross_org_project(self, director_a, org_a, project_b):
        client = api(director_a)
        resp = client.post("/api/payment-request-forms/", {
            "project": str(project_b.id), "payment_date": date.today().isoformat(),
            "currency": "IDR", "amount": "100000.00",
        }, format="json")
        assert resp.status_code == 403


@pytest.mark.django_db
class TestProjectFundAllocationRevisionCrossTenantWrite:
    def test_create_rejects_cross_org_budget_item(self, director_a, org_a, org_b, project_a):
        from apps.finance.models import BudgetCategory, BudgetItem

        fund_a = ProjectFund.objects.create(
            organization=org_a, project=project_a, source="Org A Fund", amount="1000.00", currency="USD",
        )
        category_b = BudgetCategory.objects.create(organization=org_b, code="CAT-B", name="Org B Category")
        item_b = BudgetItem.objects.create(
            category=category_b, code="BI-B", name="Org B Item", allocated_amount="500.00",
        )
        client = api(director_a)
        resp = client.post("/api/project-fund-allocation-revisions/", {
            "fund": str(fund_a.id), "action": "create",
            "proposed_data": {"budget_item": str(item_b.id), "quantity": 1, "unit_cost": 100},
        }, format="json")
        assert resp.status_code == 400
        assert resp.data["detail"] == "budget_item is invalid."
