"""Ross1000 export API view.

Endpoint: GET /api/istat/ross1000/export/

Query parameters:
    structure_id  (int, required)
    start_date    (YYYY-MM-DD, required)
    end_date      (YYYY-MM-DD, required)
    mode          ("xml" | "soap", optional, default "xml")

Response:
    application/xml  — plain Ross1000 XML
    text/xml         — SOAP envelope (mode=soap)

This view is completely isolated from:
- TXT export (/api/istat/export)
- C59 XML export (/api/istat/xml/c59-export/)
- Guest XML export (/api/istat/xml/guest-export/)
"""

from __future__ import annotations

import logging

from django.core.exceptions import PermissionDenied
from django.http import Http404, HttpResponse
from drf_spectacular.utils import OpenApiExample, OpenApiParameter, OpenApiResponse, extend_schema
from rest_framework import serializers, status
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from istat.ross1000.api.serializers import Ross1000ExportRequestSerializer
from istat.ross1000.exceptions import Ross1000ValidationError
from istat.ross1000.services.export_service import Ross1000ExportService
from structures.models import Structure


logger = logging.getLogger(__name__)


def _get_accessible_structure_or_raise(*, user, structure_id: int) -> Structure:
    structure = Structure.objects.filter(id=structure_id).first()
    if structure is None:
        raise Http404("Structure not found.")
    has_access = (
        structure.user_id == user.id
        or structure.structure_users.filter(user=user).exists()
    )
    if not has_access:
        raise PermissionDenied("You do not have access to this structure.")
    return structure


class Ross1000ExportAPIView(APIView):
    """Download a Ross1000 XML/SOAP movement export for a date range."""

    permission_classes = [IsAuthenticated]

    @extend_schema(
        tags=["Ross1000"],
        summary="Download Ross1000 movement XML export (Regione Liguria)",
        description=(
            "Generates a Ross1000-compatible XML export for the given structure "
            "and date range. One <movimento> block is produced per calendar day, "
            "including empty days. Arrivals and departures are reported separately. "
            "Use mode=soap to wrap the payload in a SOAP 1.1 envelope."
        ),
        parameters=[
            OpenApiParameter(
                name="structure_id",
                type=int,
                location=OpenApiParameter.QUERY,
                required=True,
                description="Structure ID to export.",
            ),
            OpenApiParameter(
                name="start_date",
                type=str,
                location=OpenApiParameter.QUERY,
                required=True,
                description="First day of the reporting period (YYYY-MM-DD, inclusive).",
            ),
            OpenApiParameter(
                name="end_date",
                type=str,
                location=OpenApiParameter.QUERY,
                required=True,
                description="Last day of the reporting period (YYYY-MM-DD, inclusive).",
            ),
            OpenApiParameter(
                name="mode",
                type=str,
                location=OpenApiParameter.QUERY,
                required=False,
                description="Export mode: 'xml' (default) or 'soap' envelope.",
            ),
        ],
        examples=[
            OpenApiExample(
                "Ross1000 XML export — April 2026",
                value={
                    "structure_id": 1,
                    "start_date": "2026-04-01",
                    "end_date": "2026-04-30",
                    "mode": "xml",
                },
            ),
            OpenApiExample(
                "Ross1000 SOAP export",
                value={
                    "structure_id": 1,
                    "start_date": "2026-04-01",
                    "end_date": "2026-04-30",
                    "mode": "soap",
                },
            ),
        ],
        responses={
            200: OpenApiResponse(
                description=(
                    "Downloadable Ross1000 XML (application/xml) or "
                    "SOAP envelope (text/xml)"
                )
            ),
            400: OpenApiResponse(description="Validation or business-rule error"),
            403: OpenApiResponse(description="Permission denied"),
            404: OpenApiResponse(description="Structure not found"),
            500: OpenApiResponse(description="Unexpected server error"),
        },
    )
    def get(self, request):
        # Validate query parameters
        req_serializer = Ross1000ExportRequestSerializer(data=request.query_params)
        if not req_serializer.is_valid():
            return Response(req_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

        params = req_serializer.validated_data
        structure_id = params["structure_id"]
        start_date = params["start_date"]
        end_date = params["end_date"]
        mode = params.get("mode", "xml")

        log_ctx = {
            "user_id": request.user.id,
            "structure_id": structure_id,
            "start_date": start_date.isoformat(),
            "end_date": end_date.isoformat(),
            "mode": mode,
            "export_type": "ross1000",
        }

        try:
            _get_accessible_structure_or_raise(
                user=request.user,
                structure_id=structure_id,
            )

            service = Ross1000ExportService()
            result = service.export(
                structure_id=structure_id,
                start_date=start_date,
                end_date=end_date,
                mode=mode,
            )

        except serializers.ValidationError as exc:
            return Response(exc.detail, status=status.HTTP_400_BAD_REQUEST)

        except Ross1000ValidationError as exc:
            logger.warning(
                "Ross1000 export API failed",
                extra={**log_ctx, "status": "failure", "error": str(exc)},
            )
            return Response({"detail": str(exc)}, status=status.HTTP_400_BAD_REQUEST)

        except PermissionDenied as exc:
            return Response({"detail": str(exc)}, status=status.HTTP_403_FORBIDDEN)

        except Http404 as exc:
            return Response({"detail": str(exc)}, status=status.HTTP_404_NOT_FOUND)

        except Exception:
            logger.exception(
                "Ross1000 export API unexpected failure",
                extra={**log_ctx, "status": "failure"},
            )
            return Response(
                {"detail": "An unexpected error occurred."},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

        logger.info(
            "Ross1000 export API succeeded",
            extra={
                **log_ctx,
                "filename": result.filename,
                "day_count": result.day_count,
                "status": "success",
            },
        )

        response = HttpResponse(
            result.content.encode("utf-8"),
            content_type=result.content_type,
        )
        response["Content-Disposition"] = f'attachment; filename="{result.filename}"'
        return response
