from rest_framework import status
from rest_framework.exceptions import ValidationError
from rest_framework.viewsets import ModelViewSet
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.filters import SearchFilter, OrderingFilter
from django_filters.rest_framework import DjangoFilterBackend
from apps.companies.repositories import ServiceRepository
from apps.companies.serializers import (
    ServiceSerializer,
    ServiceWithPriceSerializer,
    ServiceWithPriceUpdateSerializer, ServiceListSerializer,
)
from apps.companies.services import ServiceDomainService, ServicePriceDomainService
from utils.paginations import LimitOffsetPagination


class ServiceViewSet(ModelViewSet):
    serializer_class = ServiceSerializer
    permission_classes = [IsAuthenticated]
    pagination_class = LimitOffsetPagination

    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    filterset_fields = ["is_active"]
    search_fields = ["name", "code"]
    ordering_fields = ["id", "name", "code"]
    ordering = ["-created_at"]

    def get_queryset(self):
        return ServiceRepository.get_services(
            self.request.user.active_company
        )

    def get_serializer_class(self):
        if self.action == "list":
            return ServiceListSerializer
        return ServiceSerializer

    def perform_create(self, serializer):
        service = ServiceDomainService.create_service(
            name=serializer.validated_data["name"],
            description=serializer.validated_data.get("description"),
            company=self.request.user.active_company,
        )
        serializer.instance = service

    def perform_update(self, serializer):
        serializer.save()

    @action(methods=["post"], detail=False, url_path="create-with-price")
    def create_with_price(self, request):
        """
        Create a Service and its initial ServicePrice in one request.
        """
        serializer = ServiceWithPriceSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        data = serializer.validated_data
        company = request.user.active_company

        try:
            ServiceDomainService.create_service_with_price(
                name=data["name"],
                description=data.get("description"),
                company=company,
                price_data=data["price"]
            )
        except ValidationError as e:
            return Response(e.detail, status=status.HTTP_400_BAD_REQUEST)

        return Response(status=status.HTTP_201_CREATED)

    @action(methods=["put", "patch"], detail=True, url_path="update-with-price")
    def update_with_price(self, request, pk=None):
        """
        Update a Service and its current ServicePrice at the same time.
        """
        serializer = ServiceWithPriceUpdateSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        data = serializer.validated_data

        service = self.get_object()
        company = request.user.active_company

        service_name = data.get("name", service.name)
        service_description = data.get("description", service.description)
        is_active = data.get("is_active", service.is_active)

        try:
            service = ServiceDomainService.update_service(
                pk=pk,
                name=service_name,
                description=service_description,
                company=company,
                is_active=is_active
            )

            price_data = data["price"]
            current_price = service.prices.filter(
                company=company,
                is_active=True
            ).order_by("-effective_from").first()

            if current_price:
                _ = ServicePriceDomainService.update_price(
                    pk=current_price.pk,
                    service=service,
                    company=company,
                    **price_data
                )
            else:
                _ = ServicePriceDomainService.create_price(
                    service=service,
                    company=company,
                    **price_data
                )
        except ValidationError as e:
            return Response(e.detail, status=status.HTTP_400_BAD_REQUEST)

        return Response(status=status.HTTP_200_OK)
