"""
PM Module — API Integration Tests.

تست‌های یکپارچگی برای API ماژول مدیریت پروژه.
"""
import uuid
from datetime import date, timedelta
from decimal import Decimal

import pytest
from django.urls import reverse

pytestmark = pytest.mark.django_db


# ═══════════════════════════════════════════════════════════
# 1) Project API
# ═══════════════════════════════════════════════════════════

class TestProjectAPI:
    URL = "/api/v1/pm/projects/"

    def test_list_projects(self, auth_client, project):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create_project(self, auth_client, user):
        data = {
            "code": "PRJ-NEW",
            "title": "پروژه جدید",
            "project_type": "project",
            "priority": "medium",
            "planned_start": str(date.today()),
            "planned_end": str(date.today() + timedelta(days=60)),
            "total_budget": "500000000",
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_retrieve_project(self, auth_client, project):
        url = f"{self.URL}{project.pk}/"
        resp = auth_client.get(url)
        assert resp.status_code == 200

    def test_update_project(self, auth_client, project):
        url = f"{self.URL}{project.pk}/"
        resp = auth_client.patch(url, {"title": "عنوان جدید"}, format="json")
        assert resp.status_code == 200

    def test_delete_project(self, auth_client, project):
        url = f"{self.URL}{project.pk}/"
        resp = auth_client.delete(url)
        assert resp.status_code in (200, 204)

    def test_project_dashboard(self, auth_client, project):
        url = f"{self.URL}{project.pk}/dashboard/"
        resp = auth_client.get(url)
        assert resp.status_code == 200

    def test_project_statistics(self, auth_client, project):
        url = f"{self.URL}statistics/"
        resp = auth_client.get(url)
        assert resp.status_code == 200

    def test_project_change_status(self, auth_client, project):
        url = f"{self.URL}{project.pk}/change-status/"
        resp = auth_client.post(url, {"status": "active"}, format="json")
        # May succeed or fail based on status transition rules
        assert resp.status_code in (200, 400)

    def test_list_unauthenticated(self, api_client):
        resp = api_client.get(self.URL)
        assert resp.status_code in (401, 403)


# ═══════════════════════════════════════════════════════════
# 2) Task API
# ═══════════════════════════════════════════════════════════

class TestTaskAPI:
    URL = "/api/v1/pm/tasks/"

    def test_list_tasks(self, auth_client, task_a):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create_task(self, auth_client, project):
        data = {
            "project": str(project.pk),
            "code": "T-NEW",
            "title": "فعالیت جدید",
            "task_type": "task",
            "duration": 5,
            "planned_start": str(date.today()),
            "planned_end": str(date.today() + timedelta(days=4)),
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_retrieve_task(self, auth_client, task_a):
        url = f"{self.URL}{task_a.pk}/"
        resp = auth_client.get(url)
        assert resp.status_code == 200

    def test_update_task(self, auth_client, task_a):
        url = f"{self.URL}{task_a.pk}/"
        resp = auth_client.patch(url, {"title": "عنوان تغییریافته"}, format="json")
        assert resp.status_code == 200

    def test_delete_task(self, auth_client, task_a):
        url = f"{self.URL}{task_a.pk}/"
        resp = auth_client.delete(url)
        assert resp.status_code in (200, 204)

    def test_task_tree(self, auth_client, project, task_a):
        url = f"{self.URL}tree/"
        resp = auth_client.get(url, {"project": str(project.pk)})
        assert resp.status_code == 200

    def test_task_change_status(self, auth_client, task_a):
        url = f"{self.URL}{task_a.pk}/change-status/"
        resp = auth_client.post(url, {"status": "in_progress"}, format="json")
        assert resp.status_code in (200, 400)


# ═══════════════════════════════════════════════════════════
# 3) Dependency API
# ═══════════════════════════════════════════════════════════

class TestDependencyAPI:
    URL = "/api/v1/pm/dependencies/"

    def test_list(self, auth_client, dependency_fs):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client, project, task_a, task_b):
        data = {
            "project": str(project.pk),
            "predecessor": str(task_a.pk),
            "successor": str(task_b.pk),
            "dependency_type": "FS",
            "lag_days": 1,
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)


# ═══════════════════════════════════════════════════════════
# 4) Resource API
# ═══════════════════════════════════════════════════════════

class TestResourceAPI:
    URL = "/api/v1/pm/resources/"

    def test_list(self, auth_client, resource_human):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client):
        data = {
            "code": "RES-NEW",
            "name": "منبع جدید",
            "resource_type": "human",
            "standard_rate": "600000",
            "overtime_rate": "900000",
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_retrieve(self, auth_client, resource_human):
        url = f"{self.URL}{resource_human.pk}/"
        resp = auth_client.get(url)
        assert resp.status_code == 200


# ═══════════════════════════════════════════════════════════
# 5) Budget API
# ═══════════════════════════════════════════════════════════

class TestBudgetAPI:
    URL = "/api/v1/pm/budgets/"

    def test_list(self, auth_client, budget):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client, project):
        data = {
            "project": str(project.pk),
            "name": "بودجه جدید",
            "original_budget": "2000000000",
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_budget_summary(self, auth_client, budget):
        url = f"{self.URL}summary/?project={budget.project_id}"
        resp = auth_client.get(url)
        assert resp.status_code == 200


# ═══════════════════════════════════════════════════════════
# 6) Cost Entry API
# ═══════════════════════════════════════════════════════════

class TestCostEntryAPI:
    URL = "/api/v1/pm/cost-entries/"

    def test_list(self, auth_client, cost_entry):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client, project, budget):
        data = {
            "project": str(project.pk),
            "budget": str(budget.pk),
            "description": "هزینه جدید",
            "amount": "10000000",
            "cost_type": "fixed",
            "entry_date": str(date.today()),
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)


# ═══════════════════════════════════════════════════════════
# 7) Risk API
# ═══════════════════════════════════════════════════════════

class TestRiskAPI:
    URL = "/api/v1/pm/risks/"

    def test_list(self, auth_client, risk):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client, project_active):
        data = {
            "project": str(project_active.pk),
            "code": "RSK-NEW",
            "title": "ریسک جدید",
            "category": "cost",
            "probability": "medium",
            "impact": "major",
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_risk_matrix(self, auth_client, risk):
        url = f"{self.URL}matrix/?project={risk.project_id}"
        resp = auth_client.get(url)
        assert resp.status_code == 200


# ═══════════════════════════════════════════════════════════
# 8) Baseline API
# ═══════════════════════════════════════════════════════════

class TestBaselineAPI:
    URL = "/api/v1/pm/baselines/"

    def test_list(self, auth_client, baseline):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client, project_active):
        data = {
            "project": str(project_active.pk),
            "name": "خط مبنا جدید",
            "baseline_type": "revised",
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)


# ═══════════════════════════════════════════════════════════
# 9) Calendar API
# ═══════════════════════════════════════════════════════════

class TestCalendarAPI:
    URL = "/api/v1/pm/calendars/"

    def test_list(self, auth_client, calendar):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client):
        data = {
            "name": "تقویم جدید",
            "working_days": [0, 1, 2, 3, 5],
            "hours_per_day": 8,
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)


# ═══════════════════════════════════════════════════════════
# 10) Change Request API
# ═══════════════════════════════════════════════════════════

class TestChangeRequestAPI:
    URL = "/api/v1/pm/change-requests/"

    def test_list(self, auth_client, change_request):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client, project_active):
        data = {
            "project": str(project_active.pk),
            "code": "CR-NEW",
            "title": "درخواست تغییر جدید",
            "description": "شرح",
            "priority": "medium",
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)


# ═══════════════════════════════════════════════════════════
# 11) Timesheet API
# ═══════════════════════════════════════════════════════════

class TestTimesheetAPI:
    URL = "/api/v1/pm/timesheets/"

    def test_list(self, auth_client, timesheet):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200

    def test_create(self, auth_client, project, task_a):
        data = {
            "project": str(project.pk),
            "task": str(task_a.pk),
            "work_date": str(date.today()),
            "regular_hours": "8",
        }
        resp = auth_client.post(self.URL, data, format="json")
        assert resp.status_code in (200, 201)

    def test_approve_timesheet(self, auth_client, timesheet):
        # Change to submitted first
        timesheet.status = "submitted"
        timesheet.save()
        url = f"{self.URL}{timesheet.pk}/approve/"
        resp = auth_client.post(url, format="json")
        assert resp.status_code in (200, 400)


# ═══════════════════════════════════════════════════════════
# 12) Project Member API
# ═══════════════════════════════════════════════════════════

class TestProjectMemberAPI:
    URL = "/api/v1/pm/project-members/"

    def test_list(self, auth_client, project_member):
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200


# ═══════════════════════════════════════════════════════════
# 13) Comment API
# ═══════════════════════════════════════════════════════════

class TestCommentAPI:
    URL = "/api/v1/pm/comments/"

    def test_list(self, auth_client, project, user, tenant):
        from modules.pm.backend.infrastructure.persistence.models import CommentModel
        CommentModel.objects.create(
            id=uuid.uuid4(), tenant=tenant,
            project=project, user=user, content="تست",
        )
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200


# ═══════════════════════════════════════════════════════════
# 14) Activity Log API
# ═══════════════════════════════════════════════════════════

class TestActivityLogAPI:
    URL = "/api/v1/pm/activity-logs/"

    def test_list(self, auth_client, project, user, tenant):
        from modules.pm.backend.infrastructure.persistence.models import ActivityLogModel
        ActivityLogModel.objects.create(
            id=uuid.uuid4(), tenant=tenant,
            project=project, user=user,
            action="test", description="تست",
        )
        resp = auth_client.get(self.URL)
        assert resp.status_code == 200
