"""Endpoints de sitemaps y de la sincronización."""

from drf_spectacular.utils import extend_schema
from rest_framework import serializers, status
from rest_framework.response import Response

from apps.core.api import BaseApiView
from apps.core.errors import NotFound, ValidationFailed
from apps.domains.api import company_domain_or_error
from apps.jobs.api import BatchSerializer
from apps.jobs.models import BatchOrigin
from apps.sitemaps.models import Sitemap
from apps.sitemaps.services import check_sitemap, queue_sync, register_sitemap


class SitemapSerializer(serializers.ModelSerializer):
    needs_submit = serializers.BooleanField(read_only=True)

    class Meta:
        model = Sitemap
        fields = [
            'id',
            'location',
            'kind',
            'source',
            'parent',
            'url_count',
            'last_read_at',
            'last_submitted_at',
            'last_submit_result',
            'last_error',
            'needs_submit',
            'created_at',
        ]


class SitemapCreateSerializer(serializers.Serializer):
    location = serializers.URLField()


class SitemapListView(BaseApiView):
    @extend_schema(responses=SitemapSerializer(many=True), tags=['sitemaps'])
    def get(self, request, domain_id):
        domain = company_domain_or_error(domain_id)
        return Response(SitemapSerializer(domain.sitemaps.all(), many=True).data)

    @extend_schema(
        request=SitemapCreateSerializer, responses={201: SitemapSerializer}, tags=['sitemaps']
    )
    def post(self, request, domain_id):
        """
        Da de alta un sitemap, después de comprobar que se puede leer (T094).

        El `422` con su motivo es la diferencia entre enterarse al pegar la
        dirección y enterarse al día siguiente, cuando el resumen del lote de la
        madrugada dice que ese archivo no se pudo descargar.
        """
        domain = company_domain_or_error(domain_id)
        location = (request.data.get('location') or '').strip()

        if not location.startswith(('http://', 'https://')):
            raise ValidationFailed(
                'La dirección del sitemap tiene que ser completa, empezando por https://.',
                field='location',
            )

        check_sitemap(domain, location)
        sitemap = register_sitemap(domain, location)
        return Response(SitemapSerializer(sitemap).data, status=status.HTTP_201_CREATED)


class SitemapDetailView(BaseApiView):
    @extend_schema(responses={204: None}, tags=['sitemaps'])
    def delete(self, request, domain_id, sitemap_id):
        """
        Deja de seguir un sitemap. Las URLs que declaraba conservan su historial.

        Sólo se pueden quitar los registrados a mano: los descubiertos dentro de
        un índice volverían a aparecer en la próxima lectura, así que borrarlos
        daría la falsa impresión de haber hecho algo.
        """
        domain = company_domain_or_error(domain_id)
        sitemap = Sitemap.objects.filter(id=sitemap_id, domain=domain).first()
        if sitemap is None:
            raise NotFound('Ese sitemap no existe en este dominio.')

        if sitemap.source != 'DECLARED':
            raise ValidationFailed(
                'Ese sitemap se descubrió dentro de un índice, así que volvería a aparecer en '
                'la próxima lectura. Quitá el índice que lo declara.',
                field='sitemap_id',
            )

        sitemap.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)


class DomainSyncView(BaseApiView):
    @extend_schema(request=None, responses={202: BatchSerializer}, tags=['sitemaps'])
    def post(self, request, domain_id):
        """
        Encola la sincronización y devuelve el lote en cola.

        Devuelve 202 y no 200: el trabajo se encoló, no terminó. Responder 200
        con el lote en cola invitaría a leer «listo» donde dice «empezó».

        Y ahora encola de verdad. Hasta hace poco corría la sincronización
        entera dentro de la petición —leer cada sitemap, enviar los que
        cambiaron— y contestaba `202` igual: un sitio con muchos sitemaps se
        pasaba del tiempo de espera, y la respuesta afirmaba algo que no había
        pasado.
        """
        replay = self.replay(request)
        if replay is not None:
            return replay

        domain = company_domain_or_error(domain_id)
        batch = queue_sync(domain, origin=BatchOrigin.API)

        response = Response(BatchSerializer(batch).data, status=status.HTTP_202_ACCEPTED)
        return self.store(request, response)
