"""
CLM API Views - v1.

ویوهای REST API ماژول مدیریت قراردادها.
"""
from datetime import date, timedelta
from uuid import uuid4

from django.db.models import Q, Sum, Count
from rest_framework import viewsets, status, filters
from rest_framework.decorators import action
from rest_framework.response import Response
from django_filters.rest_framework import DjangoFilterBackend

from ...infrastructure.persistence.models import (
    ContractModel,
    ContractPartyModel,
    ContractClauseModel,
    ContractMilestoneModel,
    ContractAmendmentModel,
    ContractTemplateModel,
    ContractRenewalModel,
)
from .serializers import (
    ContractSerializer,
    ContractListSerializer,
    ContractCreateSerializer,
    ContractStatusActionSerializer,
    ContractPartySerializer,
    ContractClauseSerializer,
    ContractMilestoneSerializer,
    MilestoneCompleteSerializer,
    ContractAmendmentSerializer,
    AmendmentApproveSerializer,
    AmendmentRejectSerializer,
    ContractTemplateSerializer,
    ContractTemplateListSerializer,
    ContractRenewalSerializer,
    RenewContractSerializer,
)
from .permissions import (
    CanManageContracts,
    CanApproveContracts,
    CanManageTemplates,
    CanManageAmendments,
    CanViewReports,
)


class TenantQuerySetMixin:
    """فیلتر خودکار بر اساس 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 = {"id": uuid4()}
        if hasattr(self.request, "tenant"):
            kwargs["tenant"] = self.request.tenant
        if hasattr(serializer.Meta.model, "created_by"):
            kwargs["created_by"] = self.request.user.id
        serializer.save(**kwargs)


# ═══════════════════════════════════════════════════
# Contract Template
# ═══════════════════════════════════════════════════

class ContractTemplateViewSet(TenantQuerySetMixin, viewsets.ModelViewSet):
    """
    API مدیریت قالب‌های قرارداد.

    list: لیست قالب‌ها
    create: ایجاد قالب جدید
    retrieve: جزئیات قالب
    update: بروزرسانی قالب
    destroy: حذف قالب
    """

    queryset = ContractTemplateModel.objects.all()
    permission_classes = [CanManageTemplates]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ["category", "contract_type", "is_active"]
    search_fields = ["name", "name_en", "description"]
    ordering_fields = ["name", "usage_count", "created_at"]
    ordering = ["name"]

    def get_serializer_class(self):
        if self.action == "list":
            return ContractTemplateListSerializer
        return ContractTemplateSerializer


# ═══════════════════════════════════════════════════
# Contract
# ═══════════════════════════════════════════════════

class ContractViewSet(TenantQuerySetMixin, viewsets.ModelViewSet):
    """
    API مدیریت قراردادها.

    list: لیست قراردادها
    create: ایجاد قرارداد
    retrieve: جزئیات قرارداد
    update: بروزرسانی قرارداد
    destroy: حذف قرارداد (فقط پیش‌نویس)
    """

    queryset = ContractModel.objects.all()
    permission_classes = [CanManageContracts]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ["category", "contract_type", "status", "priority", "is_active"]
    search_fields = ["contract_number", "title", "reference_number", "tags"]
    ordering_fields = ["contract_number", "title", "total_value", "start_date", "end_date", "created_at"]
    ordering = ["-created_at"]

    def get_serializer_class(self):
        if self.action == "list":
            return ContractListSerializer
        if self.action == "create":
            return ContractCreateSerializer
        return ContractSerializer

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        if instance.status != "DRAFT":
            return Response(
                {"error": {"code": "INVALID_STATE", "message": "فقط قراردادهای پیش‌نویس قابل حذف هستند"}},
                status=status.HTTP_422_UNPROCESSABLE_ENTITY,
            )
        return super().destroy(request, *args, **kwargs)

    @action(detail=True, methods=["post"], url_path="submit-for-approval")
    def submit_for_approval(self, request, pk=None):
        """ارسال قرارداد برای تأیید."""
        contract = self.get_object()
        if contract.status != "DRAFT":
            return Response(
                {"error": {"code": "INVALID_STATE", "message": "فقط قراردادهای پیش‌نویس قابل ارسال برای تأیید هستند"}},
                status=status.HTTP_422_UNPROCESSABLE_ENTITY,
            )
        contract.status = "PENDING_APPROVAL"
        contract.save(update_fields=["status", "updated_at"])
        return Response(ContractSerializer(contract).data)

    @action(detail=True, methods=["post"], permission_classes=[CanApproveContracts])
    def approve(self, request, pk=None):
        """تأیید قرارداد."""
        contract = self.get_object()
        if contract.status not in ("DRAFT", "PENDING_APPROVAL"):
            return Response(
                {"error": {"code": "INVALID_STATE", "message": "فقط قراردادهای در انتظار تأیید قابل تأیید هستند"}},
                status=status.HTTP_422_UNPROCESSABLE_ENTITY,
            )
        contract.status = "APPROVED"
        contract.save(update_fields=["status", "updated_at"])
        return Response(ContractSerializer(contract).data)

    @action(detail=True, methods=["post"], permission_classes=[CanApproveContracts])
    def reject(self, request, pk=None):
        """رد قرارداد."""
        contract = self.get_object()
        if contract.status != "PENDING_APPROVAL":
            return Response(
                {"error": {"code": "INVALID_STATE", "message": "فقط قراردادهای در انتظار تأیید قابل رد هستند"}},
                status=status.HTTP_422_UNPROCESSABLE_ENTITY,
            )
        contract.status = "DRAFT"
        contract.save(update_fields=["status", "updated_at"])
        return Response(ContractSerializer(contract).data)

    @action(detail=True, methods=["post"])
    def activate(self, request, pk=None):
        """فعال‌سازی قرارداد."""
        contract = self.get_object()
        if contract.status != "APPROVED":
            return Response(
                {"error": {"code": "INVALID_STATE", "message": "فقط قراردادهای تأیید شده قابل فعال‌سازی هستند"}},
                status=status.HTTP_422_UNPROCESSABLE_ENTITY,
            )
        contract.status = "ACTIVE"
        contract.save(update_fields=["status", "updated_at"])
        return Response(ContractSerializer(contract).data)

    @action(detail=True, methods=["post"])
    def suspend(self, request, pk=None):
        """تعلیق قرارداد."""
        contract = self.get_object()
        if contract.status != "ACTIVE":
            return Response(
                {"error": {"code": "INVALID_STATE", "message": "فقط قراردادهای فعال قابل تعلیق هستند"}},
                status=status.HTTP_422_UNPROCESSABLE_ENTITY,
            )
        contract.status = "SUSPENDED"
        contract.save(update_fields=["status", "updated_at"])
        return Response(ContractSerializer(contract).data)

    @action(detail=True, methods=["post"])
    def resume(self, request, pk=None):
        """ازسرگیری قرارداد."""
        contract = self.get_object()
        if contract.status != "SUSPENDED":
            return Response(
                {"error": {"code": "INVALID_STATE", "message": "فقط قراردادهای تعلیق‌شده قابل ازسرگیری هستند"}},
                status=status.HTTP_422_UNPROCESSABLE_ENTITY,
            )
        contract.status = "ACTIVE"
        contract.save(update_fields=["status", "updated_at"])
        return Response(ContractSerializer(contract).data)

    @action(detail=True, methods=["post"])
    def terminate(self, request, pk=None):
        """خاتمه قرارداد."""
        serializer = ContractStatusActionSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        contract = self.get_object()
        if contract.status not in ("ACTIVE", "SUSPENDED"):
            return Response(
                {"error": {"code": "INVALID_STATE", "message": "فقط قراردادهای فعال یا تعلیق‌شده قابل خاتمه هستند"}},
                status=status.HTTP_422_UNPROCESSABLE_ENTITY,
            )
        contract.status = "TERMINATED"
        contract.save(update_fields=["status", "updated_at"])
        return Response(ContractSerializer(contract).data)

    @action(detail=True, methods=["post"])
    def complete(self, request, pk=None):
        """اتمام قرارداد."""
        contract = self.get_object()
        if contract.status != "ACTIVE":
            return Response(
                {"error": {"code": "INVALID_STATE", "message": "فقط قراردادهای فعال قابل اتمام هستند"}},
                status=status.HTTP_422_UNPROCESSABLE_ENTITY,
            )
        contract.status = "COMPLETED"
        contract.save(update_fields=["status", "updated_at"])
        return Response(ContractSerializer(contract).data)

    @action(detail=True, methods=["post"])
    def cancel(self, request, pk=None):
        """لغو قرارداد."""
        contract = self.get_object()
        if contract.status in ("COMPLETED", "TERMINATED", "CANCELLED"):
            return Response(
                {"error": {"code": "INVALID_STATE", "message": "قرارداد قابل لغو نیست"}},
                status=status.HTTP_422_UNPROCESSABLE_ENTITY,
            )
        contract.status = "CANCELLED"
        contract.save(update_fields=["status", "updated_at"])
        return Response(ContractSerializer(contract).data)

    @action(detail=True, methods=["post"])
    def renew(self, request, pk=None):
        """تمدید قرارداد."""
        contract = self.get_object()
        if contract.status not in ("ACTIVE", "EXPIRED"):
            return Response(
                {"error": {"code": "INVALID_STATE", "message": "فقط قراردادهای فعال یا منقضی قابل تمدید هستند"}},
                status=status.HTTP_422_UNPROCESSABLE_ENTITY,
            )
        if contract.max_renewals > 0 and contract.renewals_count >= contract.max_renewals:
            return Response(
                {"error": {"code": "MAX_RENEWALS", "message": "تعداد تمدید به حداکثر رسیده"}},
                status=status.HTTP_422_UNPROCESSABLE_ENTITY,
            )
        serializer = RenewContractSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        renewal = ContractRenewalModel.objects.create(
            id=uuid4(),
            tenant=contract.tenant,
            contract=contract,
            renewal_number=contract.renewals_count + 1,
            old_start_date=contract.start_date,
            old_end_date=contract.end_date,
            new_start_date=contract.end_date or date.today(),
            new_end_date=serializer.validated_data["new_end_date"],
            old_value=contract.total_value,
            new_value=serializer.validated_data.get("new_value", contract.total_value),
            notes=serializer.validated_data.get("notes", ""),
            status="APPROVED",
            approved_by=request.user.id,
            approved_at=date.today(),
        )

        contract.start_date = renewal.new_start_date
        contract.end_date = renewal.new_end_date
        contract.expiry_date = renewal.new_end_date
        if renewal.new_value:
            contract.total_value = renewal.new_value
        contract.renewals_count += 1
        if contract.status == "EXPIRED":
            contract.status = "ACTIVE"
        contract.save()

        return Response(ContractSerializer(contract).data)

    @action(detail=False, methods=["get"], url_path="expiring-soon")
    def expiring_soon(self, request):
        """قراردادهای رو به انقضا."""
        days = int(request.query_params.get("days", 30))
        threshold = date.today() + timedelta(days=days)
        qs = self.get_queryset().filter(
            status="ACTIVE",
            expiry_date__lte=threshold,
            expiry_date__gte=date.today(),
        )
        serializer = ContractListSerializer(qs, many=True)
        return Response({"data": serializer.data})

    @action(detail=False, methods=["get"], permission_classes=[CanViewReports])
    def dashboard(self, request):
        """داشبورد قراردادها."""
        qs = self.get_queryset()
        by_status = dict(qs.values_list("status").annotate(count=Count("id")).values_list("status", "count"))
        by_category = dict(qs.values_list("category").annotate(count=Count("id")).values_list("category", "count"))
        total_value = qs.filter(status="ACTIVE").aggregate(total=Sum("total_value"))["total"] or 0

        expiring_30 = qs.filter(
            status="ACTIVE",
            expiry_date__lte=date.today() + timedelta(days=30),
            expiry_date__gte=date.today(),
        ).count()

        overdue_milestones = ContractMilestoneModel.objects.filter(
            contract__in=qs.filter(status="ACTIVE"),
            status__in=["PENDING", "IN_PROGRESS"],
            due_date__lt=date.today(),
        ).count()

        return Response({
            "data": {
                "by_status": by_status,
                "by_category": by_category,
                "total_active_value": float(total_value),
                "expiring_in_30_days": expiring_30,
                "overdue_milestones": overdue_milestones,
                "total_contracts": qs.count(),
            }
        })


# ═══════════════════════════════════════════════════
# Contract Party
# ═══════════════════════════════════════════════════

class ContractPartyViewSet(TenantQuerySetMixin, viewsets.ModelViewSet):
    """API مدیریت طرف‌های قرارداد."""

    queryset = ContractPartyModel.objects.all()
    serializer_class = ContractPartySerializer
    permission_classes = [CanManageContracts]
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ["contract", "party_role"]


# ═══════════════════════════════════════════════════
# Contract Clause
# ═══════════════════════════════════════════════════

class ContractClauseViewSet(TenantQuerySetMixin, viewsets.ModelViewSet):
    """API مدیریت بندهای قرارداد."""

    queryset = ContractClauseModel.objects.all()
    serializer_class = ContractClauseSerializer
    permission_classes = [CanManageContracts]
    filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
    filterset_fields = ["contract", "clause_type"]
    ordering = ["order"]

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        if instance.is_mandatory:
            return Response(
                {"error": {"code": "MANDATORY_CLAUSE", "message": "بندهای اجباری قابل حذف نیستند"}},
                status=status.HTTP_422_UNPROCESSABLE_ENTITY,
            )
        return super().destroy(request, *args, **kwargs)


# ═══════════════════════════════════════════════════
# Contract Milestone
# ═══════════════════════════════════════════════════

class ContractMilestoneViewSet(TenantQuerySetMixin, viewsets.ModelViewSet):
    """API مدیریت مراحل قرارداد."""

    queryset = ContractMilestoneModel.objects.all()
    serializer_class = ContractMilestoneSerializer
    permission_classes = [CanManageContracts]
    filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
    filterset_fields = ["contract", "milestone_type", "status"]
    ordering = ["order"]

    @action(detail=True, methods=["post"])
    def complete(self, request, pk=None):
        """تکمیل مرحله."""
        milestone = self.get_object()
        if milestone.status in ("COMPLETED", "CANCELLED"):
            return Response(
                {"error": {"code": "INVALID_STATE", "message": "این مرحله قبلاً تکمیل یا لغو شده"}},
                status=status.HTTP_422_UNPROCESSABLE_ENTITY,
            )
        serializer = MilestoneCompleteSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        milestone.status = "COMPLETED"
        milestone.actual_date = serializer.validated_data.get("actual_date", date.today())
        milestone.accepted_by = request.user.id
        milestone.accepted_at = date.today()
        milestone.save()
        return Response(ContractMilestoneSerializer(milestone).data)

    @action(detail=False, methods=["get"])
    def overdue(self, request):
        """مراحل عقب‌افتاده."""
        qs = self.get_queryset().filter(
            status__in=["PENDING", "IN_PROGRESS"],
            due_date__lt=date.today(),
        )
        serializer = ContractMilestoneSerializer(qs, many=True)
        return Response({"data": serializer.data})


# ═══════════════════════════════════════════════════
# Contract Amendment
# ═══════════════════════════════════════════════════

class ContractAmendmentViewSet(TenantQuerySetMixin, viewsets.ModelViewSet):
    """API مدیریت الحاقیه‌ها."""

    queryset = ContractAmendmentModel.objects.all()
    serializer_class = ContractAmendmentSerializer
    permission_classes = [CanManageAmendments]
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ["contract", "amendment_type", "status"]

    def perform_create(self, serializer):
        contract = serializer.validated_data["contract"]
        next_number = contract.amendments.count() + 1
        kwargs = {
            "id": uuid4(),
            "amendment_number": next_number,
            "created_by": self.request.user.id,
        }
        if hasattr(self.request, "tenant"):
            kwargs["tenant"] = self.request.tenant
        serializer.save(**kwargs)

    @action(detail=True, methods=["post"], permission_classes=[CanApproveContracts])
    def approve(self, request, pk=None):
        """تأیید الحاقیه."""
        amendment = self.get_object()
        if amendment.status != "PENDING_APPROVAL":
            return Response(
                {"error": {"code": "INVALID_STATE", "message": "فقط الحاقیه‌های در انتظار تأیید قابل تأیید هستند"}},
                status=status.HTTP_422_UNPROCESSABLE_ENTITY,
            )
        amendment.status = "APPROVED"
        amendment.approved_by = request.user.id
        amendment.approved_at = date.today()
        amendment.save()

        # Apply amendment to contract
        contract = amendment.contract
        if amendment.new_total_value is not None:
            contract.total_value = amendment.new_total_value
        if amendment.new_end_date is not None:
            contract.end_date = amendment.new_end_date
            contract.expiry_date = amendment.new_end_date
        contract.save()
        amendment.status = "APPLIED"
        amendment.save(update_fields=["status"])

        return Response(ContractAmendmentSerializer(amendment).data)

    @action(detail=True, methods=["post"], permission_classes=[CanApproveContracts])
    def reject(self, request, pk=None):
        """رد الحاقیه."""
        amendment = self.get_object()
        if amendment.status != "PENDING_APPROVAL":
            return Response(
                {"error": {"code": "INVALID_STATE", "message": "فقط الحاقیه‌های در انتظار تأیید قابل رد هستند"}},
                status=status.HTTP_422_UNPROCESSABLE_ENTITY,
            )
        serializer = AmendmentRejectSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        amendment.status = "REJECTED"
        amendment.rejected_by = request.user.id
        amendment.rejected_reason = serializer.validated_data["reason"]
        amendment.save()
        return Response(ContractAmendmentSerializer(amendment).data)


# ═══════════════════════════════════════════════════
# Contract Renewal
# ═══════════════════════════════════════════════════

class ContractRenewalViewSet(TenantQuerySetMixin, viewsets.ReadOnlyModelViewSet):
    """API مشاهده تمدیدها (فقط خواندنی — تمدید از Contract endpoint)."""

    queryset = ContractRenewalModel.objects.all()
    serializer_class = ContractRenewalSerializer
    permission_classes = [CanManageContracts]
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ["contract", "status"]
