"""
PPM Module — API Integration Tests.

تست‌های یکپارچگی برای API ماژول مدیریت پرتفولیو و برنامه.
"""
import uuid
from datetime import date, timedelta
from decimal import Decimal

import pytest

pytestmark = pytest.mark.django_db

BASE = "/api/v1/ppm"


# ═══════════════════════════════════════════════════
# 1) Portfolio API
# ═══════════════════════════════════════════════════

class TestPortfolioAPI:
    URL = f"{BASE}/portfolios/"

    def test_list(self, auth_client, portfolio):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client):
        data = {
            "code": "PF-NEW",
            "name": "پرتفولیو جدید",
            "status": "draft",
            "total_budget": "2000000000",
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_retrieve(self, auth_client, portfolio):
        url = f"{self.URL}{portfolio.pk}/"
        resp = auth_client.get(url)
        assert resp.status_code == 200

    def test_update(self, auth_client, portfolio):
        url = f"{self.URL}{portfolio.pk}/"
        resp = auth_client.patch(url, {"name": "نام جدید"}, format="json")
        assert resp.status_code == 200

    def test_delete(self, auth_client, portfolio):
        url = f"{self.URL}{portfolio.pk}/"
        resp = auth_client.delete(url)
        assert resp.status_code in (200, 204)

    def test_unauthenticated(self, api_client):
        resp = api_client.get(self.URL)
        assert resp.status_code in (401, 403)


# ═══════════════════════════════════════════════════
# 2) Program API
# ═══════════════════════════════════════════════════

class TestProgramAPI:
    URL = f"{BASE}/programs/"

    def test_list(self, auth_client, program):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client, portfolio):
        data = {
            "code": "PG-NEW",
            "name": "برنامه جدید",
            "portfolio": str(portfolio.pk),
            "status": "draft",
            "budget": "1000000000",
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_retrieve(self, auth_client, program):
        url = f"{self.URL}{program.pk}/"
        resp = auth_client.get(url)
        assert resp.status_code == 200

    def test_update(self, auth_client, program):
        url = f"{self.URL}{program.pk}/"
        resp = auth_client.patch(url, {"name": "نام جدید"}, format="json")
        assert resp.status_code == 200

    def test_delete(self, auth_client, program):
        url = f"{self.URL}{program.pk}/"
        resp = auth_client.delete(url)
        assert resp.status_code in (200, 204)

    def test_unauthenticated(self, api_client):
        resp = api_client.get(self.URL)
        assert resp.status_code in (401, 403)


# ═══════════════════════════════════════════════════
# 3) Program-Project API
# ═══════════════════════════════════════════════════

class TestProgramProjectAPI:
    URL = f"{BASE}/program-projects/"

    def test_list(self, auth_client, program_project):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client, program):
        data = {
            "program": str(program.pk),
            "project_id": str(uuid.uuid4()),
            "role": "supporting",
            "priority": 2,
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_unauthenticated(self, api_client):
        resp = api_client.get(self.URL)
        assert resp.status_code in (401, 403)


# ═══════════════════════════════════════════════════
# 4) Business Case API
# ═══════════════════════════════════════════════════

class TestBusinessCaseAPI:
    URL = f"{BASE}/business-cases/"

    def test_list(self, auth_client, business_case):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client, program):
        data = {
            "title": "کیس تجاری جدید",
            "program": str(program.pk),
            "total_investment": "800000000",
            "expected_revenue": "2000000000",
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_retrieve(self, auth_client, business_case):
        url = f"{self.URL}{business_case.pk}/"
        resp = auth_client.get(url)
        assert resp.status_code == 200

    def test_update(self, auth_client, business_case):
        url = f"{self.URL}{business_case.pk}/"
        resp = auth_client.patch(url, {"title": "عنوان جدید"}, format="json")
        assert resp.status_code == 200

    def test_delete(self, auth_client, business_case):
        url = f"{self.URL}{business_case.pk}/"
        resp = auth_client.delete(url)
        assert resp.status_code in (200, 204)

    def test_unauthenticated(self, api_client):
        resp = api_client.get(self.URL)
        assert resp.status_code in (401, 403)


# ═══════════════════════════════════════════════════
# 5) Cash Flow API
# ═══════════════════════════════════════════════════

class TestCashFlowAPI:
    URL = f"{BASE}/cash-flows/"

    def test_list(self, auth_client, cash_flow):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client, business_case):
        data = {
            "business_case": str(business_case.pk),
            "year": 2027,
            "investment": "300000000",
            "revenue": "800000000",
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_retrieve(self, auth_client, cash_flow):
        url = f"{self.URL}{cash_flow.pk}/"
        resp = auth_client.get(url)
        assert resp.status_code == 200

    def test_unauthenticated(self, api_client):
        resp = api_client.get(self.URL)
        assert resp.status_code in (401, 403)


# ═══════════════════════════════════════════════════
# 6) Scoring Model API
# ═══════════════════════════════════════════════════

class TestScoringModelAPI:
    URL = f"{BASE}/scoring-models/"

    def test_list(self, auth_client, scoring_model):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client, portfolio):
        data = {
            "name": "مدل جدید",
            "portfolio": str(portfolio.pk),
            "is_active": True,
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_retrieve(self, auth_client, scoring_model):
        url = f"{self.URL}{scoring_model.pk}/"
        resp = auth_client.get(url)
        assert resp.status_code == 200

    def test_unauthenticated(self, api_client):
        resp = api_client.get(self.URL)
        assert resp.status_code in (401, 403)


# ═══════════════════════════════════════════════════
# 7) Scoring Criterion API
# ═══════════════════════════════════════════════════

class TestScoringCriterionAPI:
    URL = f"{BASE}/scoring-criteria/"

    def test_list(self, auth_client, scoring_criterion):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client, scoring_model):
        data = {
            "scoring_model": str(scoring_model.pk),
            "name": "معیار مالی",
            "weight": "0.30",
            "category": "financial",
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_unauthenticated(self, api_client):
        resp = api_client.get(self.URL)
        assert resp.status_code in (401, 403)


# ═══════════════════════════════════════════════════
# 8) Project Score API
# ═══════════════════════════════════════════════════

class TestProjectScoreAPI:
    URL = f"{BASE}/project-scores/"

    def test_list(self, auth_client, project_score):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client, scoring_model, scoring_criterion):
        data = {
            "scoring_model": str(scoring_model.pk),
            "project_id": str(uuid.uuid4()),
            "criterion": str(scoring_criterion.pk),
            "score": "7.50",
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_unauthenticated(self, api_client):
        resp = api_client.get(self.URL)
        assert resp.status_code in (401, 403)


# ═══════════════════════════════════════════════════
# 9) Benefit Plan API
# ═══════════════════════════════════════════════════

class TestBenefitPlanAPI:
    URL = f"{BASE}/benefit-plans/"

    def test_list(self, auth_client, benefit_plan):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client, program, portfolio):
        data = {
            "name": "برنامه منافع جدید",
            "program": str(program.pk),
            "portfolio": str(portfolio.pk),
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_retrieve(self, auth_client, benefit_plan):
        url = f"{self.URL}{benefit_plan.pk}/"
        resp = auth_client.get(url)
        assert resp.status_code == 200

    def test_unauthenticated(self, api_client):
        resp = api_client.get(self.URL)
        assert resp.status_code in (401, 403)


# ═══════════════════════════════════════════════════
# 10) Benefit API
# ═══════════════════════════════════════════════════

class TestBenefitAPI:
    URL = f"{BASE}/benefits/"

    def test_list(self, auth_client, benefit):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client, benefit_plan):
        data = {
            "benefit_plan": str(benefit_plan.pk),
            "title": "کاهش هزینه‌ها",
            "benefit_type": "financial",
            "target_value": "2000000000",
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_retrieve(self, auth_client, benefit):
        url = f"{self.URL}{benefit.pk}/"
        resp = auth_client.get(url)
        assert resp.status_code == 200

    def test_unauthenticated(self, api_client):
        resp = api_client.get(self.URL)
        assert resp.status_code in (401, 403)


# ═══════════════════════════════════════════════════
# 11) Benefit Measurement API
# ═══════════════════════════════════════════════════

class TestBenefitMeasurementAPI:
    URL = f"{BASE}/benefit-measurements/"

    def test_list(self, auth_client, benefit_measurement):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client, benefit):
        data = {
            "benefit": str(benefit.pk),
            "measurement_date": str(date.today()),
            "value": "2500000000",
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_unauthenticated(self, api_client):
        resp = api_client.get(self.URL)
        assert resp.status_code in (401, 403)


# ═══════════════════════════════════════════════════
# 12) Capacity Plan API
# ═══════════════════════════════════════════════════

class TestCapacityPlanAPI:
    URL = f"{BASE}/capacity-plans/"

    def test_list(self, auth_client, capacity_plan):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client, portfolio):
        data = {
            "name": "طرح ظرفیت جدید",
            "portfolio": str(portfolio.pk),
            "period_start": str(date.today()),
            "period_end": str(date.today() + timedelta(days=90)),
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_retrieve(self, auth_client, capacity_plan):
        url = f"{self.URL}{capacity_plan.pk}/"
        resp = auth_client.get(url)
        assert resp.status_code == 200

    def test_unauthenticated(self, api_client):
        resp = api_client.get(self.URL)
        assert resp.status_code in (401, 403)


# ═══════════════════════════════════════════════════
# 13) Resource Demand API
# ═══════════════════════════════════════════════════

class TestResourceDemandAPI:
    URL = f"{BASE}/resource-demands/"

    def test_list(self, auth_client, resource_demand):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client, capacity_plan):
        data = {
            "capacity_plan": str(capacity_plan.pk),
            "resource_type": "مدیریت پروژه",
            "demand_hours": "320.00",
            "period": "1405-Q2",
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_unauthenticated(self, api_client):
        resp = api_client.get(self.URL)
        assert resp.status_code in (401, 403)


# ═══════════════════════════════════════════════════
# 14) Resource Supply API
# ═══════════════════════════════════════════════════

class TestResourceSupplyAPI:
    URL = f"{BASE}/resource-supplies/"

    def test_list(self, auth_client, resource_supply):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client, capacity_plan):
        data = {
            "capacity_plan": str(capacity_plan.pk),
            "resource_type": "مدیریت پروژه",
            "available_hours": "400.00",
            "period": "1405-Q2",
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_unauthenticated(self, api_client):
        resp = api_client.get(self.URL)
        assert resp.status_code in (401, 403)


# ═══════════════════════════════════════════════════
# 15) Cross-Project Dependency API
# ═══════════════════════════════════════════════════

class TestCrossProjectDependencyAPI:
    URL = f"{BASE}/dependencies/"

    def test_list(self, auth_client, cross_project_dependency):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client):
        data = {
            "predecessor_project_id": str(uuid.uuid4()),
            "successor_project_id": str(uuid.uuid4()),
            "dependency_type": "SS",
            "lag_days": 0,
            "status": "active",
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_retrieve(self, auth_client, cross_project_dependency):
        url = f"{self.URL}{cross_project_dependency.pk}/"
        resp = auth_client.get(url)
        assert resp.status_code == 200

    def test_unauthenticated(self, api_client):
        resp = api_client.get(self.URL)
        assert resp.status_code in (401, 403)


# ═══════════════════════════════════════════════════
# 16) PPM Document API
# ═══════════════════════════════════════════════════

class TestPPMDocumentAPI:
    URL = f"{BASE}/documents/"

    def test_list(self, auth_client, ppm_document):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client, portfolio):
        data = {
            "entity_type": "portfolio",
            "entity_id": str(portfolio.pk),
            "document_id": str(uuid.uuid4()),
            "title": "سند جدید",
            "document_code": "DOC-NEW",
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_retrieve(self, auth_client, ppm_document):
        url = f"{self.URL}{ppm_document.pk}/"
        resp = auth_client.get(url)
        assert resp.status_code == 200

    def test_unauthenticated(self, api_client):
        resp = api_client.get(self.URL)
        assert resp.status_code in (401, 403)
