"""
PPM API v1 — Views

ViewSetهای DRF ماژول مدیریت پرتفولیو و برنامه.
"""
from rest_framework import viewsets, status, filters
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from django_filters.rest_framework import DjangoFilterBackend

from ...infrastructure.persistence.models import (
    PortfolioModel,
    ProgramModel,
    ProgramProjectModel,
    BusinessCaseModel,
    CashFlowProjectionModel,
    ScoringModelModel,
    ScoringCriterionModel,
    ProjectScoreModel,
    BenefitPlanModel,
    BenefitModel,
    BenefitMeasurementModel,
    CapacityPlanModel,
    ResourceDemandModel,
    ResourceSupplyModel,
    CrossProjectDependencyModel,
    PPMDocumentModel,
)
from .serializers import (
    PortfolioListSerializer, PortfolioDetailSerializer,
    PortfolioCreateSerializer, PortfolioStatusSerializer,
    ProgramListSerializer, ProgramDetailSerializer,
    ProgramCreateSerializer, ProgramStatusSerializer,
    ProgramProjectListSerializer, ProgramProjectCreateSerializer,
    BusinessCaseListSerializer, BusinessCaseDetailSerializer,
    BusinessCaseCreateSerializer, BusinessCaseStatusSerializer,
    CashFlowListSerializer, CashFlowCreateSerializer,
    FinancialEvaluationSerializer,
    ScoringModelListSerializer, ScoringModelDetailSerializer,
    ScoringModelCreateSerializer,
    ScoringCriterionListSerializer, ScoringCriterionCreateSerializer,
    ProjectScoreListSerializer, ProjectScoreCreateSerializer,
    ProjectRankingSerializer,
    BenefitPlanListSerializer, BenefitPlanDetailSerializer,
    BenefitPlanCreateSerializer,
    BenefitListSerializer, BenefitDetailSerializer,
    BenefitCreateSerializer, BenefitStatusSerializer,
    BenefitMeasurementListSerializer, BenefitMeasurementCreateSerializer,
    CapacityPlanListSerializer, CapacityPlanDetailSerializer,
    CapacityPlanCreateSerializer,
    ResourceDemandListSerializer, ResourceDemandCreateSerializer,
    ResourceSupplyListSerializer, ResourceSupplyCreateSerializer,
    CapacityGapSerializer, BottleneckSerializer,
    CrossProjectDependencyListSerializer, CrossProjectDependencyDetailSerializer,
    CrossProjectDependencyCreateSerializer, DependencyStatusSerializer,
    CircularDependencySerializer, CriticalChainLinkSerializer,
    ImpactAnalysisInputSerializer, ImpactResultSerializer,
    PPMDocumentListSerializer, PPMDocumentCreateSerializer,
)
from .permissions import (
    PortfolioPermission,
    ProgramPermission,
    ProgramProjectPermission,
    BusinessCasePermission,
    CashFlowPermission,
    ScoringModelPermission,
    ScoringCriterionPermission,
    ProjectScorePermission,
    BenefitPlanPermission,
    BenefitPermission,
    BenefitMeasurementPermission,
    CapacityPlanPermission,
    ResourceDemandPermission,
    ResourceSupplyPermission,
    CrossProjectDependencyPermission,
    PPMDocumentPermission,
)


class TenantFilterMixin:
    """Mixin — فیلتر خودکار queryset بر اساس tenant."""

    def get_queryset(self):
        qs = super().get_queryset()
        if hasattr(self.request, "tenant"):
            return qs.filter(tenant=self.request.tenant)
        return qs

    def perform_create(self, serializer):
        kwargs = {}
        if hasattr(self.request, "tenant"):
            kwargs["tenant"] = self.request.tenant
        serializer.save(**kwargs)


# ═══════════════════════════════════════════════════
# Portfolio ViewSet
# ═══════════════════════════════════════════════════

class PortfolioViewSet(TenantFilterMixin, viewsets.ModelViewSet):
    """CRUD پرتفولیو + عملیات تغییر وضعیت."""

    queryset = PortfolioModel.objects.select_related("owner", "parent").all()
    permission_classes = [IsAuthenticated, PortfolioPermission]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ["status", "review_cycle", "risk_tolerance", "parent", "owner"]
    search_fields = ["code", "name", "description"]
    ordering_fields = ["code", "name", "status", "created_at", "total_budget"]
    ordering = ["-created_at"]

    def get_serializer_class(self):
        if self.action == "create":
            return PortfolioCreateSerializer
        if self.action == "retrieve":
            return PortfolioDetailSerializer
        if self.action == "change_status":
            return PortfolioStatusSerializer
        return PortfolioListSerializer

    @action(detail=True, methods=["post"], url_path="change-status")
    def change_status(self, request, pk=None):
        """تغییر وضعیت پرتفولیو."""
        portfolio = self.get_object()
        serializer = PortfolioStatusSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        portfolio.status = serializer.validated_data["status"]
        portfolio.save(update_fields=["status", "updated_at"])
        return Response(PortfolioDetailSerializer(portfolio).data)

    @action(detail=True, methods=["get"], url_path="children")
    def children(self, request, pk=None):
        """لیست پرتفولیوهای زیرمجموعه."""
        portfolio = self.get_object()
        children = self.get_queryset().filter(parent=portfolio)
        serializer = PortfolioListSerializer(children, many=True)
        return Response(serializer.data)

    @action(detail=False, methods=["get"], url_path="tree")
    def tree(self, request):
        """درخت سلسله مراتبی پرتفولیوها (ریشه‌ها)."""
        roots = self.get_queryset().filter(parent__isnull=True)
        serializer = PortfolioListSerializer(roots, many=True)
        return Response(serializer.data)


# ═══════════════════════════════════════════════════
# Program ViewSet
# ═══════════════════════════════════════════════════

class ProgramViewSet(TenantFilterMixin, viewsets.ModelViewSet):
    """CRUD برنامه + عملیات تغییر وضعیت + مدیریت پروژه‌ها."""

    queryset = ProgramModel.objects.select_related("portfolio", "manager").all()
    permission_classes = [IsAuthenticated, ProgramPermission]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ["status", "portfolio", "manager", "risk_level"]
    search_fields = ["code", "name", "description", "objectives"]
    ordering_fields = ["code", "name", "status", "created_at", "budget", "progress"]
    ordering = ["-created_at"]

    def get_serializer_class(self):
        if self.action == "create":
            return ProgramCreateSerializer
        if self.action == "retrieve":
            return ProgramDetailSerializer
        if self.action == "change_status":
            return ProgramStatusSerializer
        return ProgramListSerializer

    @action(detail=True, methods=["post"], url_path="change-status")
    def change_status(self, request, pk=None):
        """تغییر وضعیت برنامه."""
        program = self.get_object()
        serializer = ProgramStatusSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        program.status = serializer.validated_data["status"]
        program.save(update_fields=["status", "updated_at"])
        return Response(ProgramDetailSerializer(program).data)

    @action(detail=True, methods=["get"], url_path="projects")
    def projects(self, request, pk=None):
        """لیست پروژه‌های برنامه."""
        program = self.get_object()
        qs = ProgramProjectModel.objects.filter(program=program)
        if hasattr(request, "tenant"):
            qs = qs.filter(tenant=request.tenant)
        serializer = ProgramProjectListSerializer(qs, many=True)
        return Response(serializer.data)

    @action(detail=True, methods=["post"], url_path="add-project")
    def add_project(self, request, pk=None):
        """افزودن پروژه به برنامه."""
        program = self.get_object()
        data = request.data.copy()
        data["program"] = program.pk
        serializer = ProgramProjectCreateSerializer(data=data)
        serializer.is_valid(raise_exception=True)
        kwargs = {}
        if hasattr(request, "tenant"):
            kwargs["tenant"] = request.tenant
        serializer.save(**kwargs)
        return Response(
            ProgramProjectListSerializer(serializer.instance).data,
            status=status.HTTP_201_CREATED,
        )

    @action(detail=True, methods=["post"], url_path="remove-project")
    def remove_project(self, request, pk=None):
        """حذف پروژه از برنامه."""
        program = self.get_object()
        project_id = request.data.get("project_id")
        if not project_id:
            return Response(
                {"error": {"code": "missing_project_id", "message": "شناسه پروژه الزامی است."}},
                status=status.HTTP_400_BAD_REQUEST,
            )
        deleted, _ = ProgramProjectModel.objects.filter(
            program=program, project_id=project_id,
        ).delete()
        if not deleted:
            return Response(
                {"error": {"code": "not_found", "message": "ارتباط پروژه یافت نشد."}},
                status=status.HTTP_404_NOT_FOUND,
            )
        return Response(status=status.HTTP_204_NO_CONTENT)


# ═══════════════════════════════════════════════════
# ProgramProject ViewSet
# ═══════════════════════════════════════════════════

class ProgramProjectViewSet(TenantFilterMixin, viewsets.ModelViewSet):
    """CRUD ارتباط برنامه-پروژه."""

    queryset = ProgramProjectModel.objects.select_related("program").all()
    permission_classes = [IsAuthenticated, ProgramProjectPermission]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ["program", "project_id", "role"]
    search_fields = ["notes"]
    ordering_fields = ["priority", "created_at"]
    ordering = ["priority", "created_at"]

    def get_serializer_class(self):
        if self.action == "create":
            return ProgramProjectCreateSerializer
        return ProgramProjectListSerializer


# ═══════════════════════════════════════════════════
# BusinessCase ViewSet
# ═══════════════════════════════════════════════════

class BusinessCaseViewSet(TenantFilterMixin, viewsets.ModelViewSet):
    """CRUD کیس تجاری + submit/approve/reject + ارزیابی مالی."""

    queryset = BusinessCaseModel.objects.select_related("program", "sponsor", "prepared_by").all()
    permission_classes = [IsAuthenticated, BusinessCasePermission]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ["status", "program", "sponsor", "prepared_by"]
    search_fields = ["title", "description", "assumptions"]
    ordering_fields = ["title", "status", "total_investment", "created_at"]
    ordering = ["-created_at"]

    def get_serializer_class(self):
        if self.action == "create":
            return BusinessCaseCreateSerializer
        if self.action == "retrieve":
            return BusinessCaseDetailSerializer
        if self.action == "change_status":
            return BusinessCaseStatusSerializer
        if self.action == "evaluate":
            return FinancialEvaluationSerializer
        return BusinessCaseListSerializer

    @action(detail=True, methods=["post"], url_path="change-status")
    def change_status(self, request, pk=None):
        """تغییر وضعیت کیس تجاری (submit / approve / reject)."""
        bc = self.get_object()
        serializer = BusinessCaseStatusSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        act = serializer.validated_data["action"]

        STATUS_MAP = {
            "submit": "submitted",
            "approve": "approved",
            "reject": "rejected",
        }
        VALID_FROM = {
            "submit": ["draft"],
            "approve": ["submitted"],
            "reject": ["submitted"],
        }
        if bc.status not in VALID_FROM.get(act, []):
            return Response(
                {"error": {"code": "invalid_transition", "message": f"عملیات «{act}» از وضعیت «{bc.status}» مجاز نیست."}},
                status=status.HTTP_422_UNPROCESSABLE_ENTITY,
            )
        bc.status = STATUS_MAP[act]
        bc.save(update_fields=["status", "updated_at"])
        return Response(BusinessCaseDetailSerializer(bc).data)

    @action(detail=True, methods=["get"], url_path="evaluate")
    def evaluate(self, request, pk=None):
        """ارزیابی مالی کیس تجاری (NPV, IRR, Payback, ROI, BCR)."""
        from decimal import Decimal
        from ...domain.services.financial_evaluator import FinancialEvaluator
        from ...domain.entities.business_case import CashFlowProjection as CFEntity

        bc = self.get_object()
        discount_rate = Decimal(request.query_params.get("discount_rate", "0.10"))
        evaluator = FinancialEvaluator()

        cf_models = CashFlowProjectionModel.objects.filter(business_case=bc).order_by("year")
        cash_flows = []
        for cf in cf_models:
            cash_flows.append(CFEntity(
                tenant_id=bc.tenant_id if hasattr(bc, "tenant_id") else None,
                business_case_id=bc.id,
                year=cf.year,
                investment=cf.investment or Decimal("0"),
                revenue=cf.revenue or Decimal("0"),
                savings=cf.savings or Decimal("0"),
                operational_cost=cf.operational_cost or Decimal("0"),
            ))

        total_inv = bc.total_investment or Decimal("0")
        expected_rev = bc.expected_revenue or Decimal("0")
        expected_sav = bc.expected_savings or Decimal("0")
        net_benefit = expected_rev + expected_sav - total_inv

        result = {
            "npv": None,
            "irr": None,
            "payback_period": None,
            "roi": evaluator.calculate_roi(total_inv, net_benefit) if total_inv else None,
            "benefit_cost_ratio": None,
        }
        if cash_flows:
            result["npv"] = evaluator.calculate_npv(cash_flows, discount_rate)
            result["irr"] = evaluator.calculate_irr(cash_flows)
            result["payback_period"] = evaluator.calculate_payback_period(cash_flows)
            result["benefit_cost_ratio"] = evaluator.calculate_benefit_cost_ratio(cash_flows, discount_rate)

        serializer = FinancialEvaluationSerializer(result)
        return Response({"data": serializer.data})

    @action(detail=True, methods=["get"], url_path="cash-flows")
    def cash_flows(self, request, pk=None):
        """لیست جریان‌های نقدی کیس تجاری."""
        bc = self.get_object()
        qs = CashFlowProjectionModel.objects.filter(business_case=bc).order_by("year")
        if hasattr(request, "tenant"):
            qs = qs.filter(tenant=request.tenant)
        serializer = CashFlowListSerializer(qs, many=True)
        return Response(serializer.data)

    @action(detail=True, methods=["post"], url_path="add-cash-flow")
    def add_cash_flow(self, request, pk=None):
        """افزودن جریان نقدی جدید."""
        bc = self.get_object()
        data = request.data.copy()
        data["business_case"] = bc.pk
        serializer = CashFlowCreateSerializer(data=data)
        serializer.is_valid(raise_exception=True)
        kwargs = {}
        if hasattr(request, "tenant"):
            kwargs["tenant"] = request.tenant
        serializer.save(**kwargs)
        return Response(
            CashFlowListSerializer(serializer.instance).data,
            status=status.HTTP_201_CREATED,
        )


# ═══════════════════════════════════════════════════
# CashFlow ViewSet
# ═══════════════════════════════════════════════════

class CashFlowViewSet(TenantFilterMixin, viewsets.ModelViewSet):
    """CRUD جریان نقدی."""

    queryset = CashFlowProjectionModel.objects.select_related("business_case").all()
    permission_classes = [IsAuthenticated, CashFlowPermission]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ["business_case", "year"]
    ordering_fields = ["year", "created_at"]
    ordering = ["year"]

    def get_serializer_class(self):
        if self.action == "create":
            return CashFlowCreateSerializer
        return CashFlowListSerializer


# ═══════════════════════════════════════════════════
# ScoringModel ViewSet
# ═══════════════════════════════════════════════════

class ScoringModelViewSet(TenantFilterMixin, viewsets.ModelViewSet):
    """CRUD مدل امتیازدهی + فعال/غیرفعال + معیارها + رتبه‌بندی."""

    queryset = ScoringModelModel.objects.select_related("portfolio").all()
    permission_classes = [IsAuthenticated, ScoringModelPermission]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ["is_active", "portfolio"]
    search_fields = ["name", "description"]
    ordering_fields = ["name", "created_at", "is_active"]
    ordering = ["-created_at"]

    def get_serializer_class(self):
        if self.action == "create":
            return ScoringModelCreateSerializer
        if self.action == "retrieve":
            return ScoringModelDetailSerializer
        return ScoringModelListSerializer

    @action(detail=True, methods=["post"], url_path="activate")
    def activate(self, request, pk=None):
        """فعال‌سازی مدل امتیازدهی."""
        sm = self.get_object()
        sm.is_active = True
        sm.save(update_fields=["is_active", "updated_at"])
        return Response(ScoringModelDetailSerializer(sm).data)

    @action(detail=True, methods=["post"], url_path="deactivate")
    def deactivate(self, request, pk=None):
        """غیرفعال‌سازی مدل امتیازدهی."""
        sm = self.get_object()
        sm.is_active = False
        sm.save(update_fields=["is_active", "updated_at"])
        return Response(ScoringModelDetailSerializer(sm).data)

    @action(detail=True, methods=["get"], url_path="criteria")
    def criteria(self, request, pk=None):
        """لیست معیارهای مدل امتیازدهی."""
        sm = self.get_object()
        qs = ScoringCriterionModel.objects.filter(scoring_model=sm).order_by("order", "name")
        if hasattr(request, "tenant"):
            qs = qs.filter(tenant=request.tenant)
        serializer = ScoringCriterionListSerializer(qs, many=True)
        return Response(serializer.data)

    @action(detail=True, methods=["post"], url_path="add-criterion")
    def add_criterion(self, request, pk=None):
        """افزودن معیار به مدل."""
        sm = self.get_object()
        data = request.data.copy()
        data["scoring_model"] = sm.pk
        serializer = ScoringCriterionCreateSerializer(data=data)
        serializer.is_valid(raise_exception=True)
        kwargs = {}
        if hasattr(request, "tenant"):
            kwargs["tenant"] = request.tenant
        serializer.save(**kwargs)
        return Response(
            ScoringCriterionListSerializer(serializer.instance).data,
            status=status.HTTP_201_CREATED,
        )

    @action(detail=True, methods=["get"], url_path="rank-projects")
    def rank_projects(self, request, pk=None):
        """رتبه‌بندی پروژه‌ها بر اساس این مدل."""
        from collections import defaultdict
        from ...domain.entities.scoring import ScoringCriterion as SCEntity, ProjectScore as PSEntity
        from ...domain.services.scoring_engine import ScoringEngine

        sm = self.get_object()
        engine = ScoringEngine()

        criteria_qs = ScoringCriterionModel.objects.filter(scoring_model=sm)
        criteria = []
        for c in criteria_qs:
            criteria.append(SCEntity(
                id=c.id,
                tenant_id=c.tenant_id,
                scoring_model_id=c.scoring_model_id,
                name=c.name,
                weight=c.weight,
                scale_min=c.scale_min,
                scale_max=c.scale_max,
                category=c.category,
                order=c.order,
            ))

        score_qs = ProjectScoreModel.objects.filter(scoring_model=sm)
        scores_by_project = defaultdict(list)
        for s in score_qs:
            scores_by_project[s.project_id].append(PSEntity(
                id=s.id,
                tenant_id=s.tenant_id,
                scoring_model_id=s.scoring_model_id,
                project_id=s.project_id,
                criterion_id=s.criterion_id,
                score=s.score,
                justification=s.justification or "",
                scored_by_id=s.scored_by_id,
                scored_at=s.scored_at,
            ))

        rankings = engine.rank_projects(criteria, dict(scores_by_project))
        result = [
            {
                "project_id": str(r.project_id),
                "weighted_score": r.weighted_score,
                "rank": r.rank,
                "scores_by_category": r.scores_by_category or {},
            }
            for r in rankings
        ]
        serializer = ProjectRankingSerializer(result, many=True)
        return Response({"data": serializer.data})


# ═══════════════════════════════════════════════════
# ScoringCriterion ViewSet
# ═══════════════════════════════════════════════════

class ScoringCriterionViewSet(TenantFilterMixin, viewsets.ModelViewSet):
    """CRUD معیارهای امتیازدهی."""

    queryset = ScoringCriterionModel.objects.select_related("scoring_model").all()
    permission_classes = [IsAuthenticated, ScoringCriterionPermission]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ["scoring_model", "category"]
    search_fields = ["name", "description"]
    ordering_fields = ["order", "name", "weight", "created_at"]
    ordering = ["order", "name"]

    def get_serializer_class(self):
        if self.action == "create":
            return ScoringCriterionCreateSerializer
        return ScoringCriterionListSerializer


# ═══════════════════════════════════════════════════
# ProjectScore ViewSet
# ═══════════════════════════════════════════════════

class ProjectScoreViewSet(TenantFilterMixin, viewsets.ModelViewSet):
    """CRUD امتیازات پروژه."""

    queryset = ProjectScoreModel.objects.select_related(
        "scoring_model", "criterion", "scored_by",
    ).all()
    permission_classes = [IsAuthenticated, ProjectScorePermission]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ["scoring_model", "project_id", "criterion", "scored_by"]
    search_fields = ["justification"]
    ordering_fields = ["score", "scored_at", "created_at"]
    ordering = ["-created_at"]

    def get_serializer_class(self):
        if self.action == "create":
            return ProjectScoreCreateSerializer
        return ProjectScoreListSerializer


# ═══════════════════════════════════════════════════
# Benefit Plan ViewSet
# ═══════════════════════════════════════════════════

class BenefitPlanViewSet(TenantFilterMixin, viewsets.ModelViewSet):
    """CRUD برنامه تحقق منافع + activate/deactivate + benefits."""

    queryset = BenefitPlanModel.objects.select_related(
        "program", "portfolio",
    ).all()
    permission_classes = [IsAuthenticated, BenefitPlanPermission]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ["program", "portfolio", "is_active"]
    search_fields = ["name", "description"]
    ordering_fields = ["name", "created_at"]
    ordering = ["-created_at"]

    def get_serializer_class(self):
        if self.action == "create":
            return BenefitPlanCreateSerializer
        if self.action == "retrieve":
            return BenefitPlanDetailSerializer
        return BenefitPlanListSerializer

    @action(detail=True, methods=["post"], url_path="activate")
    def activate(self, request, pk=None):
        """فعال‌سازی برنامه تحقق منافع."""
        plan = self.get_object()
        plan.is_active = True
        plan.save()
        return Response(BenefitPlanListSerializer(plan).data)

    @action(detail=True, methods=["post"], url_path="deactivate")
    def deactivate(self, request, pk=None):
        """غیرفعال‌سازی برنامه تحقق منافع."""
        plan = self.get_object()
        plan.is_active = False
        plan.save()
        return Response(BenefitPlanListSerializer(plan).data)

    @action(detail=True, methods=["get"], url_path="benefits")
    def benefits(self, request, pk=None):
        """لیست منافع یک برنامه تحقق منافع."""
        plan = self.get_object()
        benefits = BenefitModel.objects.filter(benefit_plan=plan)
        serializer = BenefitListSerializer(benefits, many=True)
        return Response({"data": serializer.data})

    @action(detail=True, methods=["post"], url_path="add-benefit")
    def add_benefit(self, request, pk=None):
        """افزودن منفعت به برنامه تحقق منافع."""
        plan = self.get_object()
        data = request.data.copy()
        data["benefit_plan"] = plan.id
        serializer = BenefitCreateSerializer(data=data)
        serializer.is_valid(raise_exception=True)
        benefit = serializer.save(tenant=plan.tenant)
        return Response(
            BenefitListSerializer(benefit).data,
            status=status.HTTP_201_CREATED,
        )


# ═══════════════════════════════════════════════════
# Benefit ViewSet
# ═══════════════════════════════════════════════════

class BenefitViewSet(TenantFilterMixin, viewsets.ModelViewSet):
    """CRUD منافع + change_status + measurements."""

    queryset = BenefitModel.objects.select_related(
        "benefit_plan", "owner",
    ).all()
    permission_classes = [IsAuthenticated, BenefitPermission]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ["benefit_plan", "benefit_type", "status", "owner", "frequency"]
    search_fields = ["title", "description", "category"]
    ordering_fields = ["title", "target_value", "actual_value", "status", "created_at"]
    ordering = ["-created_at"]

    def get_serializer_class(self):
        if self.action == "create":
            return BenefitCreateSerializer
        if self.action == "retrieve":
            return BenefitDetailSerializer
        if self.action == "change_status":
            return BenefitStatusSerializer
        return BenefitListSerializer

    @action(detail=True, methods=["post"], url_path="change-status")
    def change_status(self, request, pk=None):
        """تغییر وضعیت منفعت: plan / realize / fail."""
        benefit = self.get_object()
        serializer = BenefitStatusSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        action_name = serializer.validated_data["action"]

        current_status = benefit.status
        if action_name == "plan" and current_status == "identified":
            benefit.status = "planned"
        elif action_name == "realize" and current_status == "planned":
            benefit.status = "realized"
        elif action_name == "fail" and current_status in ("identified", "planned"):
            benefit.status = "failed"
        else:
            return Response(
                {"error": {"code": "invalid_transition", "message": f"Cannot {action_name} from {current_status}"}},
                status=status.HTTP_400_BAD_REQUEST,
            )
        benefit.save()
        return Response(BenefitListSerializer(benefit).data)

    @action(detail=True, methods=["get"], url_path="measurements")
    def measurements(self, request, pk=None):
        """لیست اندازه‌گیری‌های یک منفعت."""
        benefit = self.get_object()
        measurements = BenefitMeasurementModel.objects.filter(benefit=benefit).order_by("-measurement_date")
        serializer = BenefitMeasurementListSerializer(measurements, many=True)
        return Response({"data": serializer.data})

    @action(detail=True, methods=["post"], url_path="add-measurement")
    def add_measurement(self, request, pk=None):
        """افزودن اندازه‌گیری جدید و بروزرسانی مقدار واقعی."""
        benefit = self.get_object()
        data = request.data.copy()
        data["benefit"] = benefit.id
        serializer = BenefitMeasurementCreateSerializer(data=data)
        serializer.is_valid(raise_exception=True)
        measurement = serializer.save(tenant=benefit.tenant)

        # Update benefit actual_value
        benefit.actual_value = measurement.value
        benefit.save()

        return Response(
            BenefitMeasurementListSerializer(measurement).data,
            status=status.HTTP_201_CREATED,
        )


# ═══════════════════════════════════════════════════
# Benefit Measurement ViewSet
# ═══════════════════════════════════════════════════

class BenefitMeasurementViewSet(TenantFilterMixin, viewsets.ModelViewSet):
    """CRUD اندازه‌گیری‌های منفعت."""

    queryset = BenefitMeasurementModel.objects.select_related(
        "benefit", "measured_by",
    ).all()
    permission_classes = [IsAuthenticated, BenefitMeasurementPermission]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ["benefit", "measured_by"]
    search_fields = ["notes"]
    ordering_fields = ["measurement_date", "value", "created_at"]
    ordering = ["-measurement_date", "-created_at"]

    def get_serializer_class(self):
        if self.action == "create":
            return BenefitMeasurementCreateSerializer
        return BenefitMeasurementListSerializer


# ═══════════════════════════════════════════════════
# Capacity Plan ViewSet
# ═══════════════════════════════════════════════════

class CapacityPlanViewSet(TenantFilterMixin, viewsets.ModelViewSet):
    """CRUD طرح ظرفیت + تحلیل تقاضا/عرضه."""

    queryset = CapacityPlanModel.objects.all()
    permission_classes = [IsAuthenticated, CapacityPlanPermission]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ["portfolio_id", "is_active"]
    search_fields = ["name", "description"]
    ordering_fields = ["name", "period_start", "period_end", "created_at"]
    ordering = ["-created_at"]

    def get_serializer_class(self):
        if self.action == "create":
            return CapacityPlanCreateSerializer
        if self.action == "retrieve":
            return CapacityPlanDetailSerializer
        return CapacityPlanListSerializer

    @action(detail=True, methods=["post"], url_path="activate")
    def activate(self, request, pk=None):
        """فعال‌سازی طرح ظرفیت."""
        plan = self.get_object()
        plan.is_active = True
        plan.save()
        return Response(CapacityPlanListSerializer(plan).data)

    @action(detail=True, methods=["post"], url_path="deactivate")
    def deactivate(self, request, pk=None):
        """غیرفعال‌سازی طرح ظرفیت."""
        plan = self.get_object()
        plan.is_active = False
        plan.save()
        return Response(CapacityPlanListSerializer(plan).data)

    @action(detail=True, methods=["get"], url_path="analyze")
    def analyze(self, request, pk=None):
        """تحلیل ظرفیت — شکاف تقاضا/عرضه و گلوگاه‌ها."""
        from ...domain.services.capacity_analyzer import CapacityAnalyzer

        plan = self.get_object()
        demands_qs = ResourceDemandModel.objects.filter(capacity_plan=plan)
        supplies_qs = ResourceSupplyModel.objects.filter(capacity_plan=plan)

        # Build simple dicts for analyzer
        demands = []
        for d in demands_qs:
            demands.append(type('D', (), {
                'resource_type': d.resource_type,
                'period': d.period,
                'demand_hours': float(d.demand_hours),
                'project_id': str(d.project_id) if d.project_id else None,
            })())
        supplies = []
        for s in supplies_qs:
            supplies.append(type('S', (), {
                'resource_type': s.resource_type,
                'period': s.period,
                'available_hours': float(s.available_hours),
            })())

        analyzer = CapacityAnalyzer()
        gaps = analyzer.calculate_demand_vs_supply(demands, supplies)
        threshold = float(request.query_params.get('threshold', 80))
        bottlenecks = analyzer.identify_bottlenecks(gaps, demands, threshold)

        return Response({
            "data": {
                "gaps": CapacityGapSerializer(gaps, many=True).data,
                "bottlenecks": BottleneckSerializer(bottlenecks, many=True).data,
            }
        })

    @action(detail=True, methods=["get"], url_path="demands")
    def demands(self, request, pk=None):
        """لیست تقاضاهای یک طرح ظرفیت."""
        plan = self.get_object()
        demands = ResourceDemandModel.objects.filter(capacity_plan=plan).order_by("period", "resource_type")
        serializer = ResourceDemandListSerializer(demands, many=True)
        return Response({"data": serializer.data})

    @action(detail=True, methods=["post"], url_path="add-demand")
    def add_demand(self, request, pk=None):
        """افزودن تقاضای منبع به طرح ظرفیت."""
        plan = self.get_object()
        data = request.data.copy()
        data["capacity_plan"] = plan.id
        serializer = ResourceDemandCreateSerializer(data=data)
        serializer.is_valid(raise_exception=True)
        demand = serializer.save(tenant=plan.tenant)
        return Response(
            ResourceDemandListSerializer(demand).data,
            status=status.HTTP_201_CREATED,
        )

    @action(detail=True, methods=["get"], url_path="supplies")
    def supplies(self, request, pk=None):
        """لیست عرضه‌های یک طرح ظرفیت."""
        plan = self.get_object()
        supplies = ResourceSupplyModel.objects.filter(capacity_plan=plan).order_by("period", "resource_type")
        serializer = ResourceSupplyListSerializer(supplies, many=True)
        return Response({"data": serializer.data})

    @action(detail=True, methods=["post"], url_path="add-supply")
    def add_supply(self, request, pk=None):
        """افزودن عرضه منبع به طرح ظرفیت."""
        plan = self.get_object()
        data = request.data.copy()
        data["capacity_plan"] = plan.id
        serializer = ResourceSupplyCreateSerializer(data=data)
        serializer.is_valid(raise_exception=True)
        supply = serializer.save(tenant=plan.tenant)
        return Response(
            ResourceSupplyListSerializer(supply).data,
            status=status.HTTP_201_CREATED,
        )


# ═══════════════════════════════════════════════════
# Resource Demand ViewSet
# ═══════════════════════════════════════════════════

class ResourceDemandViewSet(TenantFilterMixin, viewsets.ModelViewSet):
    """CRUD تقاضای منبع."""

    queryset = ResourceDemandModel.objects.all()
    permission_classes = [IsAuthenticated, ResourceDemandPermission]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ["capacity_plan", "resource_type", "project_id"]
    search_fields = ["resource_type", "notes"]
    ordering_fields = ["resource_type", "period", "demand_hours", "created_at"]
    ordering = ["period", "resource_type"]

    def get_serializer_class(self):
        if self.action == "create":
            return ResourceDemandCreateSerializer
        return ResourceDemandListSerializer


# ═══════════════════════════════════════════════════
# Resource Supply ViewSet
# ═══════════════════════════════════════════════════

class ResourceSupplyViewSet(TenantFilterMixin, viewsets.ModelViewSet):
    """CRUD عرضه منبع."""

    queryset = ResourceSupplyModel.objects.all()
    permission_classes = [IsAuthenticated, ResourceSupplyPermission]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ["capacity_plan", "resource_type"]
    search_fields = ["resource_type", "notes"]
    ordering_fields = ["resource_type", "period", "available_hours", "created_at"]
    ordering = ["period", "resource_type"]

    def get_serializer_class(self):
        if self.action == "create":
            return ResourceSupplyCreateSerializer
        return ResourceSupplyListSerializer


# ═══════════════════════════════════════════════════
# Cross-Project Dependency ViewSet
# ═══════════════════════════════════════════════════

class CrossProjectDependencyViewSet(TenantFilterMixin, viewsets.ModelViewSet):
    """CRUD وابستگی بین پروژه‌ای + تحلیل."""

    queryset = CrossProjectDependencyModel.objects.all()
    permission_classes = [IsAuthenticated, CrossProjectDependencyPermission]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = [
        "predecessor_project_id", "successor_project_id",
        "dependency_type", "status",
    ]
    search_fields = ["impact_description"]
    ordering_fields = ["dependency_type", "status", "lag_days", "created_at"]
    ordering = ["-created_at"]

    def get_serializer_class(self):
        if self.action == "create":
            return CrossProjectDependencyCreateSerializer
        if self.action == "retrieve":
            return CrossProjectDependencyDetailSerializer
        if self.action == "change_status":
            return DependencyStatusSerializer
        if self.action == "impact_analysis":
            return ImpactAnalysisInputSerializer
        return CrossProjectDependencyListSerializer

    @action(detail=True, methods=["post"], url_path="change-status")
    def change_status(self, request, pk=None):
        """تغییر وضعیت وابستگی (resolve / reactivate)."""
        dep = self.get_object()
        serializer = DependencyStatusSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        action_name = serializer.validated_data["action"]

        if action_name == "resolve" and dep.status == "active":
            dep.status = "resolved"
        elif action_name == "reactivate" and dep.status == "resolved":
            dep.status = "active"
        else:
            return Response(
                {"error": {"code": "invalid_transition", "message": f"Cannot {action_name} from {dep.status}"}},
                status=status.HTTP_400_BAD_REQUEST,
            )
        dep.save()
        return Response(CrossProjectDependencyListSerializer(dep).data)

    @action(detail=False, methods=["get"], url_path="by-project/(?P<project_id>[^/.]+)")
    def by_project(self, request, project_id=None):
        """لیست وابستگی‌های یک پروژه (predecessor یا successor)."""
        from django.db.models import Q
        deps = CrossProjectDependencyModel.objects.filter(
            Q(predecessor_project_id=project_id) | Q(successor_project_id=project_id)
        )
        if hasattr(request, "tenant"):
            deps = deps.filter(tenant=request.tenant)
        serializer = CrossProjectDependencyListSerializer(deps, many=True)
        return Response({"data": serializer.data})

    @action(detail=False, methods=["get"], url_path="circular-check")
    def circular_check(self, request):
        """تشخیص وابستگی‌های حلقوی."""
        from ...domain.services.dependency_analyzer import DependencyAnalyzer

        qs = CrossProjectDependencyModel.objects.filter(status="active")
        if hasattr(request, "tenant"):
            qs = qs.filter(tenant=request.tenant)

        analyzer = DependencyAnalyzer()
        circulars = analyzer.detect_circular_dependencies(qs)

        return Response({
            "data": CircularDependencySerializer(circulars, many=True).data,
        })

    @action(detail=False, methods=["get"], url_path="critical-chain")
    def critical_chain(self, request):
        """محاسبه زنجیره بحرانی."""
        from ...domain.services.dependency_analyzer import DependencyAnalyzer

        qs = CrossProjectDependencyModel.objects.filter(status="active")
        if hasattr(request, "tenant"):
            qs = qs.filter(tenant=request.tenant)

        analyzer = DependencyAnalyzer()
        chain = analyzer.calculate_critical_chain(qs)

        return Response({
            "data": CriticalChainLinkSerializer(chain, many=True).data,
        })

    @action(detail=False, methods=["post"], url_path="impact-analysis")
    def impact_analysis(self, request):
        """تحلیل اثر تأخیر یک پروژه بر پروژه‌های وابسته."""
        from ...domain.services.dependency_analyzer import DependencyAnalyzer

        serializer = ImpactAnalysisInputSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        qs = CrossProjectDependencyModel.objects.filter(status="active")
        if hasattr(request, "tenant"):
            qs = qs.filter(tenant=request.tenant)

        analyzer = DependencyAnalyzer()
        result = analyzer.impact_analysis(
            qs,
            serializer.validated_data["project_id"],
            serializer.validated_data["delay_days"],
        )

        return Response({
            "data": ImpactResultSerializer(result).data,
        })


# ═══════════════════════════════════════════════════
# PPM Document ViewSet
# ═══════════════════════════════════════════════════

class PPMDocumentViewSet(TenantFilterMixin, viewsets.ModelViewSet):
    """
    مدیریت اسناد پیوست‌شده به موجودیت‌های PPM.
    پیوند اسناد سرویس Document Control با پرتفولیو، برنامه و کیس تجاری.
    """
    queryset = PPMDocumentModel.objects.select_related("linked_by").all()
    permission_classes = [IsAuthenticated, PPMDocumentPermission]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ["entity_type", "entity_id", "document_id"]
    search_fields = ["title", "document_code", "notes"]
    ordering_fields = ["created_at", "title"]

    def get_serializer_class(self):
        if self.action in ("create",):
            return PPMDocumentCreateSerializer
        return PPMDocumentListSerializer

    def perform_create(self, serializer):
        serializer.save(
            linked_by=self.request.user,
            tenant=getattr(self.request, "tenant", None),
        )

    @action(detail=False, methods=["get"], url_path="by-entity/(?P<entity_type>[^/.]+)/(?P<entity_id>[^/.]+)")
    def by_entity(self, request, entity_type=None, entity_id=None):
        """دریافت تمام اسناد پیوست‌شده به یک موجودیت مشخص."""
        qs = self.get_queryset().filter(
            entity_type=entity_type,
            entity_id=entity_id,
        )
        serializer = PPMDocumentListSerializer(qs, many=True)
        return Response({"data": serializer.data})
