"""
PM Module — Model Unit Tests.

تست‌های واحد برای مدل‌های ORM ماژول مدیریت پروژه.
"""
import uuid
from datetime import date, timedelta
from decimal import Decimal

import pytest
from django.db import IntegrityError

from modules.pm.backend.infrastructure.persistence.models import (
    ProjectModel,
    TaskModel,
    DependencyModel,
    ResourceModel,
    ResourceAssignmentModel,
    BudgetModel,
    CostEntryModel,
    RiskModel,
    BaselineModel,
    CalendarModel,
    HolidayModel,
    ChangeRequestModel,
    TimesheetModel as PMTimesheetModel,
    ProjectMemberModel,
    CommentModel,
    ActivityLogModel,
)

pytestmark = pytest.mark.django_db


# ═══════════════════════════════════════════════════════════
# 1) Project Model
# ═══════════════════════════════════════════════════════════

class TestProjectModel:
    def test_create(self, project):
        assert project.pk is not None
        assert project.code == "PRJ-001"
        assert project.title == "پروژه آزمایشی"
        assert project.status == "planning"

    def test_str(self, project):
        result = str(project)
        assert project.code in result
        assert project.title in result

    def test_unique_code_per_tenant(self, tenant, user):
        ProjectModel.objects.create(
            id=uuid.uuid4(), tenant=tenant, code="UNIQ-001",
            title="اول", project_type="project", status="draft", manager=user,
        )
        with pytest.raises(IntegrityError):
            ProjectModel.objects.create(
                id=uuid.uuid4(), tenant=tenant, code="UNIQ-001",
                title="دوم", project_type="project", status="draft", manager=user,
            )

    def test_self_referencing_parent(self, tenant, project, user):
        sub = ProjectModel.objects.create(
            id=uuid.uuid4(), tenant=tenant, code="PRJ-SUB",
            title="زیرپروژه", project_type="sub_project",
            status="draft", parent=project, manager=user,
        )
        assert sub.parent == project


# ═══════════════════════════════════════════════════════════
# 2) Task & Dependency Models
# ═══════════════════════════════════════════════════════════

class TestTaskModel:
    def test_create(self, task_a):
        assert task_a.pk is not None
        assert task_a.code == "T-001"
        assert task_a.task_type == "task"

    def test_task_project_relation(self, task_a, project):
        assert task_a.project == project

    def test_milestone_creation(self, milestone):
        assert milestone.task_type == "milestone"
        assert milestone.is_milestone is True

    def test_parent_child(self, tenant, project):
        parent = TaskModel.objects.create(
            id=uuid.uuid4(), tenant=tenant, project=project,
            code="T-P", title="خلاصه", task_type="summary",
            status="not_started", sort_order=0,
        )
        child = TaskModel.objects.create(
            id=uuid.uuid4(), tenant=tenant, project=project,
            code="T-C1", title="فرزند", task_type="task",
            status="not_started", parent=parent, sort_order=1,
        )
        assert child.parent == parent


class TestDependencyModel:
    def test_create(self, dependency_fs):
        assert dependency_fs.pk is not None
        assert dependency_fs.dependency_type == "FS"
        assert dependency_fs.lag_days == 0

    def test_dependency_relations(self, dependency_fs, task_a, task_b):
        assert dependency_fs.predecessor == task_a
        assert dependency_fs.successor == task_b


# ═══════════════════════════════════════════════════════════
# 3) Resource & Assignment Models
# ═══════════════════════════════════════════════════════════

class TestResourceModel:
    def test_create_human(self, resource_human):
        assert resource_human.resource_type == "human"
        assert resource_human.is_active is True
        assert resource_human.standard_rate == Decimal("500000")

    def test_create_equipment(self, resource_equipment):
        assert resource_equipment.resource_type == "equipment"

    def test_assignment(self, tenant, project, task_a, resource_human):
        assignment = ResourceAssignmentModel.objects.create(
            id=uuid.uuid4(), tenant=tenant, project=project,
            task=task_a, resource=resource_human,
            units=Decimal("100"),
            planned_hours=Decimal("80"),
        )
        assert assignment.resource == resource_human
        assert assignment.task == task_a


# ═══════════════════════════════════════════════════════════
# 4) Budget & Cost Models
# ═══════════════════════════════════════════════════════════

class TestBudgetModel:
    def test_create(self, budget):
        assert budget.name == "بودجه اصلی"
        assert budget.original_budget == Decimal("1000000000")
        assert budget.is_active is True

    def test_budget_project_relation(self, budget, project):
        assert budget.project == project


class TestCostEntryModel:
    def test_create(self, cost_entry):
        assert cost_entry.amount == Decimal("50000000")
        assert cost_entry.cost_type == "material"

    def test_cost_budget_relation(self, cost_entry, budget):
        assert cost_entry.budget == budget


# ═══════════════════════════════════════════════════════════
# 5) Risk Model
# ═══════════════════════════════════════════════════════════

class TestRiskModel:
    def test_create(self, risk):
        assert risk.code == "RSK-001"
        assert risk.probability == "high"
        assert risk.impact == "moderate"
        assert risk.risk_score == 12
        assert risk.status == "identified"

    def test_risk_project_relation(self, risk, project_active):
        assert risk.project == project_active


# ═══════════════════════════════════════════════════════════
# 6) Calendar & Holiday Models
# ═══════════════════════════════════════════════════════════

class TestCalendarModel:
    def test_create(self, calendar):
        assert calendar.name == "تقویم کاری تست"
        assert calendar.hours_per_day == 8
        assert calendar.is_default is True

    def test_holiday(self, tenant, calendar):
        holiday = HolidayModel.objects.create(
            id=uuid.uuid4(), tenant=tenant,
            calendar=calendar,
            name="نوروز",
            holiday_date=date(2025, 3, 21),
            is_recurring=True,
        )
        assert holiday.calendar == calendar
        assert holiday.is_recurring is True


# ═══════════════════════════════════════════════════════════
# 7) Change Request Model
# ═══════════════════════════════════════════════════════════

class TestChangeRequestModel:
    def test_create(self, change_request):
        assert change_request.code == "CR-001"
        assert change_request.priority == "high"
        assert change_request.status == "draft"


# ═══════════════════════════════════════════════════════════
# 8) Baseline Model
# ═══════════════════════════════════════════════════════════

class TestBaselineModel:
    def test_create(self, baseline):
        assert baseline.name == "خط مبنا اولیه"
        assert baseline.baseline_type == "initial"
        assert baseline.is_active is True


# ═══════════════════════════════════════════════════════════
# 9) Timesheet Model
# ═══════════════════════════════════════════════════════════

class TestTimesheetModel:
    def test_create(self, timesheet):
        assert timesheet.regular_hours == Decimal("8")
        assert timesheet.status == "draft"

    def test_timesheet_task_relation(self, timesheet, task_a):
        assert timesheet.task == task_a


# ═══════════════════════════════════════════════════════════
# 10) Project Member & Comment Models
# ═══════════════════════════════════════════════════════════

class TestProjectMemberModel:
    def test_create(self, project_member):
        assert project_member.role == "member"


class TestCommentModel:
    def test_create(self, tenant, project, user):
        comment = CommentModel.objects.create(
            id=uuid.uuid4(), tenant=tenant,
            project=project, user=user,
            content="نظر تست",
        )
        assert comment.content == "نظر تست"
        assert comment.is_deleted is False

    def test_soft_delete(self, tenant, project, user):
        comment = CommentModel.objects.create(
            id=uuid.uuid4(), tenant=tenant,
            project=project, user=user,
            content="حذف شدنی",
        )
        comment.is_deleted = True
        comment.save()
        assert comment.is_deleted is True


class TestActivityLogModel:
    def test_create(self, tenant, project, user):
        log = ActivityLogModel.objects.create(
            id=uuid.uuid4(), tenant=tenant,
            project=project, user=user,
            action="project_created",
            description="پروژه ایجاد شد",
        )
        assert log.action == "project_created"
