"""
PM Module — Pytest Fixtures.

فیکسچرهای مشترک برای تست‌های ماژول مدیریت پروژه.
"""
import sys
from pathlib import Path
import uuid
from datetime import date, timedelta
from decimal import Decimal

# Ensure project root is on sys.path
PROJECT_ROOT = str(Path(__file__).resolve().parent.parent.parent.parent)
if PROJECT_ROOT not in sys.path:
    sys.path.insert(0, PROJECT_ROOT)

import pytest

from apps.core.tenant.models import Tenant, Domain
from apps.core.tenant.middleware import _thread_locals
from apps.core.auth.models import User

# Force import of PM views before tests
import modules.pm.backend.api.v1.views  # noqa: F401

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,
)


# ─── Tenant & Auth ──────────────────────────────────────────

@pytest.fixture(autouse=True)
def _patch_tenant_middleware(tenant, monkeypatch):
    """Ensure get_current_tenant() returns the fixture tenant."""
    from django.db import connection
    from apps.core.tenant import middleware as tenant_mw

    monkeypatch.setattr(tenant_mw, "get_current_tenant", lambda: tenant)

    if hasattr(connection, "set_tenant"):
        connection.set_tenant(tenant)

    yield

    if hasattr(_thread_locals, "tenant"):
        del _thread_locals.tenant
    if hasattr(_thread_locals, "request"):
        del _thread_locals.request


@pytest.fixture(scope="function")
def tenant(db):
    """Create a test tenant with domain."""
    t = Tenant.objects.create(
        name="PM Test Tenant",
        slug="pm-test",
        schema_name="public",
    )
    Domain.objects.create(
        domain="localhost",
        tenant=t,
        is_primary=True,
    )
    return t


@pytest.fixture
def user(tenant):
    """Create a regular user."""
    return User.objects.create_user(
        email="pm-user@example.com",
        password="testpass123",
        first_name="PM",
        last_name="User",
        tenant=tenant,
    )


@pytest.fixture
def admin_user(tenant):
    """Create a superuser."""
    return User.objects.create_superuser(
        email="pm-admin@example.com",
        password="adminpass123",
        first_name="PM",
        last_name="Admin",
        tenant=tenant,
    )


# ─── PM Domain Objects ─────────────────────────────────────

@pytest.fixture
def calendar(tenant):
    """Create a test calendar."""
    return CalendarModel.objects.create(
        id=uuid.uuid4(),
        tenant=tenant,
        name="تقویم کاری تست",
        working_days=[0, 1, 2, 3, 5],  # شنبه تا چهارشنبه + پنجشنبه
        hours_per_day=8,
        is_default=True,
    )


@pytest.fixture
def project(tenant, user):
    """Create a test project."""
    return ProjectModel.objects.create(
        id=uuid.uuid4(),
        tenant=tenant,
        code="PRJ-001",
        title="پروژه آزمایشی",
        description="پروژه تست",
        project_type="project",
        status="planning",
        priority="medium",
        planned_start=date.today(),
        planned_end=date.today() + timedelta(days=90),
        total_budget=Decimal("1000000000"),
        estimated_cost=Decimal("900000000"),
        manager=user,
    )


@pytest.fixture
def project_active(tenant, user):
    """Create an active project."""
    return ProjectModel.objects.create(
        id=uuid.uuid4(),
        tenant=tenant,
        code="PRJ-002",
        title="پروژه فعال",
        project_type="project",
        status="active",
        priority="high",
        planned_start=date.today() - timedelta(days=10),
        planned_end=date.today() + timedelta(days=80),
        actual_start=date.today() - timedelta(days=10),
        total_budget=Decimal("500000000"),
        manager=user,
    )


@pytest.fixture
def task_a(tenant, project):
    """Create a test task A."""
    return TaskModel.objects.create(
        id=uuid.uuid4(),
        tenant=tenant,
        project=project,
        code="T-001",
        title="فعالیت الف",
        task_type="task",
        status="not_started",
        planned_start=date.today(),
        planned_end=date.today() + timedelta(days=10),
        duration=10,
        sort_order=1,
        planned_cost=Decimal("50000000"),
    )


@pytest.fixture
def task_b(tenant, project, task_a):
    """Create a test task B (after A)."""
    return TaskModel.objects.create(
        id=uuid.uuid4(),
        tenant=tenant,
        project=project,
        code="T-002",
        title="فعالیت ب",
        task_type="task",
        status="not_started",
        planned_start=date.today() + timedelta(days=11),
        planned_end=date.today() + timedelta(days=20),
        duration=10,
        sort_order=2,
        planned_cost=Decimal("30000000"),
    )


@pytest.fixture
def milestone(tenant, project):
    """Create a test milestone."""
    return TaskModel.objects.create(
        id=uuid.uuid4(),
        tenant=tenant,
        project=project,
        code="M-001",
        title="مایلستون ۱",
        task_type="milestone",
        status="not_started",
        planned_start=date.today() + timedelta(days=21),
        planned_end=date.today() + timedelta(days=21),
        duration=0,
        sort_order=3,
        is_milestone=True,
    )


@pytest.fixture
def dependency_fs(tenant, project, task_a, task_b):
    """Create FS dependency: A → B."""
    return DependencyModel.objects.create(
        id=uuid.uuid4(),
        tenant=tenant,
        project=project,
        predecessor=task_a,
        successor=task_b,
        dependency_type="FS",
        lag_days=0,
    )


@pytest.fixture
def resource_human(tenant):
    """Create a human resource."""
    return ResourceModel.objects.create(
        id=uuid.uuid4(),
        tenant=tenant,
        code="RES-001",
        name="علی محمدی",
        resource_type="human",
        email="ali@example.com",
        standard_rate=Decimal("500000"),
        overtime_rate=Decimal("750000"),
        max_units=100,
        is_active=True,
    )


@pytest.fixture
def resource_equipment(tenant):
    """Create an equipment resource."""
    return ResourceModel.objects.create(
        id=uuid.uuid4(),
        tenant=tenant,
        code="RES-002",
        name="جرثقیل برجی",
        resource_type="equipment",
        standard_rate=Decimal("2000000"),
        overtime_rate=Decimal("3000000"),
        max_units=100,
        is_active=True,
    )


@pytest.fixture
def budget(tenant, project):
    """Create a test budget."""
    return BudgetModel.objects.create(
        id=uuid.uuid4(),
        tenant=tenant,
        project=project,
        name="بودجه اصلی",
        original_budget=Decimal("1000000000"),
        revised_budget=Decimal("1100000000"),
        committed_cost=Decimal("300000000"),
        actual_cost=Decimal("200000000"),
        is_active=True,
    )


@pytest.fixture
def cost_entry(tenant, project, budget):
    """Create a cost entry."""
    return CostEntryModel.objects.create(
        id=uuid.uuid4(),
        tenant=tenant,
        project=project,
        budget=budget,
        description="هزینه مصالح",
        amount=Decimal("50000000"),
        cost_type="material",
        entry_date=date.today(),
    )


@pytest.fixture
def risk(tenant, project_active, user):
    """Create a test risk."""
    return RiskModel.objects.create(
        id=uuid.uuid4(),
        tenant=tenant,
        project=project_active,
        code="RSK-001",
        title="ریسک تأخیر تأمین مصالح",
        category="technical",
        probability="high",
        impact="moderate",
        status="identified",
        response_strategy="mitigate",
        owner=user,
    )


@pytest.fixture
def change_request(tenant, project, user):
    """Create a change request."""
    return ChangeRequestModel.objects.create(
        id=uuid.uuid4(),
        tenant=tenant,
        project=project,
        code="CR-001",
        title="تغییر محدوده فاز ۲",
        description="افزودن الزامات جدید",
        priority="high",
        status="draft",
        requester=user,
    )


@pytest.fixture
def baseline(tenant, project, user):
    """Create a baseline."""
    return BaselineModel.objects.create(
        id=uuid.uuid4(),
        tenant=tenant,
        project=project,
        name="خط مبنا اولیه",
        baseline_type="initial",
        snapshot_data={"tasks": [], "budget": "1000000000"},
        is_active=True,
        created_by=user,
    )


@pytest.fixture
def timesheet(tenant, project, task_a, user):
    """Create a timesheet entry."""
    return PMTimesheetModel.objects.create(
        id=uuid.uuid4(),
        tenant=tenant,
        project=project,
        task=task_a,
        user=user,
        work_date=date.today(),
        regular_hours=Decimal("8"),
        overtime_hours=Decimal("2"),
        status="draft",
        description="کار روی فعالیت الف",
    )


@pytest.fixture
def project_member(tenant, project, user):
    """Create a project member."""
    return ProjectMemberModel.objects.create(
        id=uuid.uuid4(),
        tenant=tenant,
        project=project,
        user=user,
        role="member",
    )


# ─── API Client ─────────────────────────────────────────────

@pytest.fixture
def api_client():
    """Create DRF API client."""
    from rest_framework.test import APIClient
    return APIClient()


@pytest.fixture
def auth_client(api_client, admin_user):
    """Create authenticated API client."""
    api_client.force_authenticate(user=admin_user)
    return api_client


@pytest.fixture
def user_client(api_client, user):
    """Create authenticated API client with regular user."""
    api_client.force_authenticate(user=user)
    return api_client
