from datetime import date, datetime

from django.db.models import Subquery
from django.utils import timezone
from django.utils.decorators import method_decorator
from drf_yasg.utils import swagger_auto_schema
from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelMixin
from rest_framework.permissions import IsAuthenticatedOrReadOnly
from rest_framework.viewsets import GenericViewSet

from verify_trusted.companies.api.filters.review import ReviewFilter
from verify_trusted.companies.api.params import (
    end_date_param,
    platform_ids_param,
    rating_param,
    source_ids_param,
    start_date_param,
)
from verify_trusted.companies.api.serializers import ReviewSerializer
from verify_trusted.companies.history_types import HistoryType
from verify_trusted.companies.models import Review, Company
from verify_trusted.reviews.models import ReviewSource, Platform
from verify_trusted.users.api.paginations import ReviewResultsSetPagination
from verify_trusted.users.api.params import company_review_param
from django.db.models import Q

reviews_filter_params = [
    company_review_param,
    platform_ids_param,
    source_ids_param,
    rating_param,
    start_date_param,
    end_date_param,
]


@method_decorator(
    name='list', decorator=swagger_auto_schema(manual_parameters=reviews_filter_params)
)
class ReviewViewSet(
    CreateModelMixin,
    UpdateModelMixin,
    ListModelMixin,
    GenericViewSet,
):
    queryset = (
        Review.objects.prefetch_related('source__platform').all().order_by('display_order', '-date')
    )
    serializer_class = ReviewSerializer
    pagination_class = ReviewResultsSetPagination
    permission_classes = [
        IsAuthenticatedOrReadOnly,
    ]
    filterset_class = ReviewFilter

    def get_queryset(self):
        queryset = super().get_queryset().filter(~Q(source__platform__status=Platform.Status.HIDE_REVIEWS))
        if self.action == 'list':
            query_params = self.request.query_params

            start_date_filter = query_params.get(start_date_param.name, None)
            if start_date_filter:
                end_date_filter = query_params.get(end_date_param.name, None)
                start_date_filter = datetime.strptime(start_date_filter, '%Y-%m-%d')
                end_date_filter = (
                    end_date_filter if end_date_filter is not None else date.today()
                )
                queryset = queryset.filter(
                    date__range=[start_date_filter, end_date_filter]
                )
        return queryset

    def add_changelog(self, serializer):
        company = (
            serializer.instance.source.company
            if serializer.instance is not None
            else serializer.validated_data['source'].company
        )
        history = (
            company.history.exclude(history_change_reason=HistoryType.CLAIMED)
                .filter(history_type='~')
                .order_by('-history_date')
                .first()
        )
        if history is not None:
            history.history_date = timezone.now()
            history.save()
        else:
            company.phone = company.phone
            company.save()

    def update_company(self, company_id):
        Company.objects.filter(id=company_id).update(
            average_rating=Subquery(
                Company.objects.filter(id=company_id).with_avg_rating().values('cal_average_rating')[:1]),

            reviews_count=Subquery(
                Company.objects.filter(id=company_id).with_reviews_count().values('cal_reviews_count')[:1])
        )

    def limit_reviews_active(self, company_id):
        reviews = Review.objects.filter(
            source_id__in=Subquery(ReviewSource.objects.filter(company_id=company_id).values_list('id', flat=True)),
            is_active=True).order_by('-date_modify', '-date')
        if len(reviews) > 20:
            for review in reviews[20:]:
                review.is_active = False
                review.save()

    def perform_update(self, serializer):
        self.add_changelog(serializer)
        serializer.save()
        company_id = ReviewSource.objects.get(id=serializer.data['source']).company.id
        self.update_company(company_id)
        self.limit_reviews_active(company_id)

    def perform_create(self, serializer):
        self.add_changelog(serializer)
        serializer.save()
        company_id = ReviewSource.objects.get(id=serializer.data['source']).company.id
        self.update_company(company_id)
