"""
PPM API v1 — Serializers

سریالایزرهای DRF ماژول مدیریت پرتفولیو و برنامه.
"""
from rest_framework import serializers
from ...infrastructure.persistence.models import (
    PortfolioModel,
    ProgramModel,
    ProgramProjectModel,
    BusinessCaseModel,
    CashFlowProjectionModel,
    ScoringModelModel,
    ScoringCriterionModel,
    ProjectScoreModel,
    BenefitPlanModel,
    BenefitModel,
    BenefitMeasurementModel,
    CapacityPlanModel,
    ResourceDemandModel,
    ResourceSupplyModel,
    CrossProjectDependencyModel,
    PPMDocumentModel,
)


# ═══════════════════════════════════════════════════
# Portfolio Serializers
# ═══════════════════════════════════════════════════

class PortfolioListSerializer(serializers.ModelSerializer):
    owner_name = serializers.SerializerMethodField()

    class Meta:
        model = PortfolioModel
        fields = [
            "id", "code", "name", "description", "parent",
            "status", "strategic_alignment_score", "risk_tolerance",
            "total_budget", "allocated_budget",
            "start_date", "end_date", "review_cycle",
            "owner", "owner_name", "company_id", "org_unit_id",
            "tags", "metadata",
            "created_at", "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]

    def get_owner_name(self, obj):
        if obj.owner:
            return obj.owner.get_full_name() or obj.owner.username
        return None


class PortfolioDetailSerializer(PortfolioListSerializer):
    children_count = serializers.SerializerMethodField()

    class Meta(PortfolioListSerializer.Meta):
        fields = PortfolioListSerializer.Meta.fields + ["children_count"]

    def get_children_count(self, obj):
        return obj.children.count()


class PortfolioCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = PortfolioModel
        fields = [
            "code", "name", "description", "parent",
            "risk_tolerance", "total_budget",
            "start_date", "end_date", "review_cycle",
            "owner", "company_id", "org_unit_id",
            "tags", "metadata",
        ]


class PortfolioStatusSerializer(serializers.Serializer):
    status = serializers.ChoiceField(choices=PortfolioModel.Status.choices)


# ═══════════════════════════════════════════════════
# Program Serializers
# ═══════════════════════════════════════════════════

class ProgramListSerializer(serializers.ModelSerializer):
    manager_name = serializers.SerializerMethodField()
    portfolio_name = serializers.SerializerMethodField()

    class Meta:
        model = ProgramModel
        fields = [
            "id", "code", "name", "description",
            "portfolio", "portfolio_name",
            "manager", "manager_name",
            "status", "objectives", "expected_benefits",
            "budget", "start_date", "end_date",
            "risk_level", "progress",
            "tags", "metadata",
            "created_at", "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]

    def get_manager_name(self, obj):
        if obj.manager:
            return obj.manager.get_full_name() or obj.manager.username
        return None

    def get_portfolio_name(self, obj):
        if obj.portfolio:
            return obj.portfolio.name
        return None


class ProgramDetailSerializer(ProgramListSerializer):
    projects_count = serializers.SerializerMethodField()

    class Meta(ProgramListSerializer.Meta):
        fields = ProgramListSerializer.Meta.fields + ["projects_count"]

    def get_projects_count(self, obj):
        return obj.program_projects.count()


class ProgramCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = ProgramModel
        fields = [
            "code", "name", "description",
            "portfolio", "manager",
            "objectives", "expected_benefits",
            "budget", "start_date", "end_date",
            "risk_level",
            "tags", "metadata",
        ]


class ProgramStatusSerializer(serializers.Serializer):
    status = serializers.ChoiceField(choices=ProgramModel.Status.choices)


# ═══════════════════════════════════════════════════
# ProgramProject Serializers
# ═══════════════════════════════════════════════════

class ProgramProjectListSerializer(serializers.ModelSerializer):
    class Meta:
        model = ProgramProjectModel
        fields = [
            "id", "program", "project_id",
            "role", "priority", "notes",
            "created_at", "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]


class ProgramProjectCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = ProgramProjectModel
        fields = [
            "program", "project_id",
            "role", "priority", "notes",
        ]


# ═══════════════════════════════════════════════════
# Business Case Serializers
# ═══════════════════════════════════════════════════

class BusinessCaseListSerializer(serializers.ModelSerializer):
    sponsor_name = serializers.SerializerMethodField()
    prepared_by_name = serializers.SerializerMethodField()
    program_name = serializers.SerializerMethodField()

    class Meta:
        model = BusinessCaseModel
        fields = [
            "id", "title", "description",
            "program", "program_name",
            "project_id", "status",
            "sponsor", "sponsor_name",
            "prepared_by", "prepared_by_name",
            "strategic_fit_score",
            "total_investment", "expected_revenue", "expected_savings",
            "payback_period_months",
            "assumptions", "constraints", "risks_summary",
            "metadata",
            "created_at", "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]

    def get_sponsor_name(self, obj):
        if obj.sponsor:
            return obj.sponsor.get_full_name() or obj.sponsor.username
        return None

    def get_prepared_by_name(self, obj):
        if obj.prepared_by:
            return obj.prepared_by.get_full_name() or obj.prepared_by.username
        return None

    def get_program_name(self, obj):
        if obj.program:
            return obj.program.name
        return None


class BusinessCaseDetailSerializer(BusinessCaseListSerializer):
    cash_flows_count = serializers.SerializerMethodField()

    class Meta(BusinessCaseListSerializer.Meta):
        fields = BusinessCaseListSerializer.Meta.fields + ["cash_flows_count"]

    def get_cash_flows_count(self, obj):
        return obj.cash_flows.count()


class BusinessCaseCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = BusinessCaseModel
        fields = [
            "title", "description",
            "program", "project_id",
            "sponsor", "prepared_by",
            "strategic_fit_score",
            "total_investment", "expected_revenue", "expected_savings",
            "payback_period_months",
            "assumptions", "constraints", "risks_summary",
            "metadata",
        ]


class BusinessCaseStatusSerializer(serializers.Serializer):
    action = serializers.ChoiceField(choices=["submit", "approve", "reject"])


# ═══════════════════════════════════════════════════
# CashFlow Serializers
# ═══════════════════════════════════════════════════

class CashFlowListSerializer(serializers.ModelSerializer):
    net_cash_flow = serializers.SerializerMethodField()

    class Meta:
        model = CashFlowProjectionModel
        fields = [
            "id", "business_case", "year",
            "investment", "revenue", "savings", "operational_cost",
            "net_cash_flow",
            "created_at", "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]

    def get_net_cash_flow(self, obj):
        return (obj.revenue or 0) + (obj.savings or 0) - (obj.investment or 0) - (obj.operational_cost or 0)


class CashFlowCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = CashFlowProjectionModel
        fields = [
            "business_case", "year",
            "investment", "revenue", "savings", "operational_cost",
        ]


# ═══════════════════════════════════════════════════
# Financial Evaluation Serializer
# ═══════════════════════════════════════════════════

class FinancialEvaluationSerializer(serializers.Serializer):
    npv = serializers.DecimalField(max_digits=20, decimal_places=2, allow_null=True)
    irr = serializers.DecimalField(max_digits=10, decimal_places=4, allow_null=True)
    payback_period = serializers.DecimalField(max_digits=10, decimal_places=2, allow_null=True)
    roi = serializers.DecimalField(max_digits=10, decimal_places=4, allow_null=True)
    benefit_cost_ratio = serializers.DecimalField(max_digits=10, decimal_places=4, allow_null=True)


# ═══════════════════════════════════════════════════
# Scoring Model Serializers
# ═══════════════════════════════════════════════════

class ScoringModelListSerializer(serializers.ModelSerializer):
    criteria_count = serializers.SerializerMethodField()
    portfolio_name = serializers.SerializerMethodField()

    class Meta:
        model = ScoringModelModel
        fields = [
            "id", "name", "description",
            "portfolio", "portfolio_name",
            "is_active", "metadata",
            "criteria_count",
            "created_at", "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]

    def get_criteria_count(self, obj):
        return obj.criteria.count()

    def get_portfolio_name(self, obj):
        if obj.portfolio:
            return obj.portfolio.name
        return None


class ScoringModelDetailSerializer(ScoringModelListSerializer):
    pass


class ScoringModelCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = ScoringModelModel
        fields = [
            "name", "description",
            "portfolio", "is_active",
            "metadata",
        ]


# ═══════════════════════════════════════════════════
# Scoring Criterion Serializers
# ═══════════════════════════════════════════════════

class ScoringCriterionListSerializer(serializers.ModelSerializer):
    class Meta:
        model = ScoringCriterionModel
        fields = [
            "id", "scoring_model", "name", "description",
            "weight", "scale_min", "scale_max",
            "category", "order",
            "created_at", "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]


class ScoringCriterionCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = ScoringCriterionModel
        fields = [
            "scoring_model", "name", "description",
            "weight", "scale_min", "scale_max",
            "category", "order",
        ]


# ═══════════════════════════════════════════════════
# Project Score Serializers
# ═══════════════════════════════════════════════════

class ProjectScoreListSerializer(serializers.ModelSerializer):
    scored_by_name = serializers.SerializerMethodField()
    criterion_name = serializers.SerializerMethodField()

    class Meta:
        model = ProjectScoreModel
        fields = [
            "id", "scoring_model", "project_id",
            "criterion", "criterion_name",
            "score", "justification",
            "scored_by", "scored_by_name", "scored_at",
            "created_at", "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]

    def get_scored_by_name(self, obj):
        if obj.scored_by:
            return obj.scored_by.get_full_name() or obj.scored_by.username
        return None

    def get_criterion_name(self, obj):
        if obj.criterion:
            return obj.criterion.name
        return None


class ProjectScoreCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = ProjectScoreModel
        fields = [
            "scoring_model", "project_id",
            "criterion", "score",
            "justification", "scored_by", "scored_at",
        ]


# ═══════════════════════════════════════════════════
# Ranking Serializer
# ═══════════════════════════════════════════════════

class ProjectRankingSerializer(serializers.Serializer):
    project_id = serializers.UUIDField()
    weighted_score = serializers.DecimalField(max_digits=10, decimal_places=2)
    rank = serializers.IntegerField()
    scores_by_category = serializers.DictField(child=serializers.DecimalField(max_digits=10, decimal_places=2))


# ═══════════════════════════════════════════════════
# Benefit Plan Serializers
# ═══════════════════════════════════════════════════

class BenefitPlanListSerializer(serializers.ModelSerializer):
    benefits_count = serializers.SerializerMethodField()
    program_name = serializers.SerializerMethodField()
    portfolio_name = serializers.SerializerMethodField()

    class Meta:
        model = BenefitPlanModel
        fields = [
            "id", "name", "description",
            "program", "program_name",
            "portfolio", "portfolio_name",
            "is_active", "benefits_count",
            "metadata",
            "created_at", "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]

    def get_benefits_count(self, obj):
        return obj.benefits.count() if hasattr(obj, "benefits") else 0

    def get_program_name(self, obj):
        if obj.program:
            return obj.program.name
        return None

    def get_portfolio_name(self, obj):
        if obj.portfolio:
            return obj.portfolio.name
        return None


class BenefitPlanDetailSerializer(BenefitPlanListSerializer):
    class Meta(BenefitPlanListSerializer.Meta):
        pass


class BenefitPlanCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = BenefitPlanModel
        fields = [
            "name", "description",
            "program", "portfolio",
            "is_active", "metadata",
        ]


# ═══════════════════════════════════════════════════
# Benefit Serializers
# ═══════════════════════════════════════════════════

class BenefitListSerializer(serializers.ModelSerializer):
    owner_name = serializers.SerializerMethodField()
    realization_percentage = serializers.SerializerMethodField()

    class Meta:
        model = BenefitModel
        fields = [
            "id", "benefit_plan", "title", "description",
            "benefit_type", "category",
            "target_value", "actual_value",
            "measurement_method", "frequency",
            "owner", "owner_name",
            "status", "target_date",
            "realization_percentage",
            "metadata",
            "created_at", "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]

    def get_owner_name(self, obj):
        if obj.owner:
            return obj.owner.get_full_name() or obj.owner.username
        return None

    def get_realization_percentage(self, obj):
        if obj.target_value and obj.target_value > 0:
            return round((obj.actual_value / obj.target_value) * 100, 2)
        return 0


class BenefitDetailSerializer(BenefitListSerializer):
    class Meta(BenefitListSerializer.Meta):
        pass


class BenefitCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = BenefitModel
        fields = [
            "benefit_plan", "title", "description",
            "benefit_type", "category",
            "target_value", "actual_value",
            "measurement_method", "frequency",
            "owner", "target_date",
            "metadata",
        ]


class BenefitStatusSerializer(serializers.Serializer):
    action = serializers.ChoiceField(choices=["plan", "realize", "fail"])


# ═══════════════════════════════════════════════════
# Benefit Measurement Serializers
# ═══════════════════════════════════════════════════

class BenefitMeasurementListSerializer(serializers.ModelSerializer):
    measured_by_name = serializers.SerializerMethodField()

    class Meta:
        model = BenefitMeasurementModel
        fields = [
            "id", "benefit", "measurement_date",
            "value", "notes",
            "measured_by", "measured_by_name",
            "created_at", "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]

    def get_measured_by_name(self, obj):
        if obj.measured_by:
            return obj.measured_by.get_full_name() or obj.measured_by.username
        return None


class BenefitMeasurementCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = BenefitMeasurementModel
        fields = [
            "benefit", "measurement_date",
            "value", "notes", "measured_by",
        ]


# ═══════════════════════════════════════════════════
# Capacity Plan Serializers
# ═══════════════════════════════════════════════════

class CapacityPlanListSerializer(serializers.ModelSerializer):
    demands_count = serializers.SerializerMethodField()
    supplies_count = serializers.SerializerMethodField()

    class Meta:
        model = CapacityPlanModel
        fields = [
            "id", "name", "description", "portfolio_id",
            "period_start", "period_end", "is_active",
            "metadata",
            "demands_count", "supplies_count",
            "created_at", "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]

    def get_demands_count(self, obj):
        return obj.demands.count()

    def get_supplies_count(self, obj):
        return obj.supplies.count()


class CapacityPlanDetailSerializer(CapacityPlanListSerializer):
    demands = serializers.SerializerMethodField()
    supplies = serializers.SerializerMethodField()

    class Meta(CapacityPlanListSerializer.Meta):
        fields = CapacityPlanListSerializer.Meta.fields + ["demands", "supplies"]

    def get_demands(self, obj):
        return ResourceDemandListSerializer(obj.demands.all(), many=True).data

    def get_supplies(self, obj):
        return ResourceSupplyListSerializer(obj.supplies.all(), many=True).data


class CapacityPlanCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = CapacityPlanModel
        fields = [
            "name", "description", "portfolio_id",
            "period_start", "period_end",
            "metadata",
        ]


# ═══════════════════════════════════════════════════
# Resource Demand Serializers
# ═══════════════════════════════════════════════════

class ResourceDemandListSerializer(serializers.ModelSerializer):
    class Meta:
        model = ResourceDemandModel
        fields = [
            "id", "capacity_plan", "resource_type",
            "project_id", "demand_hours", "period",
            "notes",
            "created_at", "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]


class ResourceDemandCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = ResourceDemandModel
        fields = [
            "capacity_plan", "resource_type",
            "project_id", "demand_hours", "period",
            "notes",
        ]


# ═══════════════════════════════════════════════════
# Resource Supply Serializers
# ═══════════════════════════════════════════════════

class ResourceSupplyListSerializer(serializers.ModelSerializer):
    class Meta:
        model = ResourceSupplyModel
        fields = [
            "id", "capacity_plan", "resource_type",
            "available_hours", "period",
            "notes",
            "created_at", "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]


class ResourceSupplyCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = ResourceSupplyModel
        fields = [
            "capacity_plan", "resource_type",
            "available_hours", "period",
            "notes",
        ]


# ═══════════════════════════════════════════════════
# Capacity Analysis Serializers (read-only)
# ═══════════════════════════════════════════════════

class CapacityGapSerializer(serializers.Serializer):
    resource_type = serializers.CharField()
    period = serializers.CharField()
    total_demand = serializers.FloatField()
    total_supply = serializers.FloatField()
    gap = serializers.FloatField()
    utilization_pct = serializers.FloatField()


class BottleneckSerializer(serializers.Serializer):
    resource_type = serializers.CharField()
    period = serializers.CharField()
    gap = serializers.FloatField()
    utilization_pct = serializers.FloatField()
    severity = serializers.CharField()
    contributing_projects = serializers.ListField(child=serializers.CharField())


# ═══════════════════════════════════════════════════
# Cross-Project Dependency Serializers
# ═══════════════════════════════════════════════════

class CrossProjectDependencyListSerializer(serializers.ModelSerializer):
    class Meta:
        model = CrossProjectDependencyModel
        fields = [
            "id",
            "predecessor_project_id", "successor_project_id",
            "predecessor_milestone_id", "successor_milestone_id",
            "dependency_type", "lag_days",
            "status", "impact_description",
            "metadata",
            "created_at", "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]


class CrossProjectDependencyDetailSerializer(CrossProjectDependencyListSerializer):
    pass


class CrossProjectDependencyCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = CrossProjectDependencyModel
        fields = [
            "predecessor_project_id", "successor_project_id",
            "predecessor_milestone_id", "successor_milestone_id",
            "dependency_type", "lag_days",
            "impact_description", "metadata",
        ]


class DependencyStatusSerializer(serializers.Serializer):
    action = serializers.ChoiceField(choices=["resolve", "reactivate"])


# ─── Analysis Serializers (read-only) ────────────

class CircularDependencySerializer(serializers.Serializer):
    cycle = serializers.ListField(child=serializers.CharField())
    description = serializers.CharField()


class CriticalChainLinkSerializer(serializers.Serializer):
    project_id = serializers.CharField()
    predecessor_id = serializers.CharField(allow_null=True)
    dependency_type = serializers.CharField()
    lag_days = serializers.IntegerField()
    total_slack = serializers.IntegerField()


class ImpactAnalysisInputSerializer(serializers.Serializer):
    project_id = serializers.CharField()
    delay_days = serializers.IntegerField(min_value=1)


class ImpactResultSerializer(serializers.Serializer):
    delayed_project_id = serializers.CharField()
    delay_days = serializers.IntegerField()
    affected_projects = serializers.ListField()
    total_cascade_days = serializers.IntegerField()


# ═══════════════════════════════════════════════════
# PPM Document Serializers
# ═══════════════════════════════════════════════════

class PPMDocumentListSerializer(serializers.ModelSerializer):
    linked_by_display = serializers.SerializerMethodField()

    class Meta:
        model = PPMDocumentModel
        fields = [
            "id", "entity_type", "entity_id", "document_id",
            "title", "document_code", "linked_by", "linked_by_display",
            "notes", "created_at",
        ]

    def get_linked_by_display(self, obj):
        return obj.linked_by.get_full_name() if obj.linked_by else None


class PPMDocumentCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = PPMDocumentModel
        fields = [
            "entity_type", "entity_id", "document_id",
            "title", "document_code", "notes",
        ]
