import re
from collections import defaultdict
from decimal import Decimal

from django.db import models
from django.db.models import Q, Sum
from django.db.models.functions import Coalesce
from django.http import HttpResponse
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from rest_framework.exceptions import ValidationError
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from checkpoint.models import CheckPoint
from users.permissions import IsAdminUserRole

from .dashboard_views import (
    NEPALI_MONTHS,
    _apply_bs_date_range_filter,
    _fiscal_year_label,
    _fiscal_year_qs,
    _get_bs_date_range,
    _get_nepali_year,
    _monthly_data_to_csv,
    _monthly_data_to_pdf_bytes,
    _monthly_data_to_print_html,
)
from .models import (
    DestructionSubmission,
    HealthInspectionSubmission,
    ImportSubmission,
    RevenueFineSubmission,
)
from .unit_conversion import UnitConversionNormalizer

QUARTER_MONTHS = {
    1: [4, 5, 6],
    2: [7, 8, 9],
    3: [10, 11, 12],
    4: [1, 2, 3],
}

QUARTER_LABELS = {
    1: "First Quarter",
    2: "Second Quarter",
    3: "Third Quarter",
    4: "Fourth Quarter",
}

BUFFALO_KEYWORDS = ("buffalo", "heifer")
GOAT_KEYWORDS = ("goat", "sheep")


_fiscal_year_param = OpenApiParameter(
    name="fiscal_year",
    type=str,
    location=OpenApiParameter.QUERY,
    required=False,
    description="Fiscal year label, e.g. 2082/83. Takes precedence over `year`.",
)

_year_param = OpenApiParameter(
    name="year",
    type=int,
    location=OpenApiParameter.QUERY,
    required=False,
    description="Fiscal year start (B.S.), e.g. 2082 for FY 2082/83.",
)

_from_bs_date_param = OpenApiParameter(
    name="from_bs_date",
    type=str,
    location=OpenApiParameter.QUERY,
    required=False,
    description="Inclusive start B.S. date: YYYY-MM-DD, YYYY/MM/DD, DD-MM-YYYY, DD/MM/YYYY.",
)

_to_bs_date_param = OpenApiParameter(
    name="to_bs_date",
    type=str,
    location=OpenApiParameter.QUERY,
    required=False,
    description="Inclusive end B.S. date: YYYY-MM-DD, YYYY/MM/DD, DD-MM-YYYY, DD/MM/YYYY.",
)

_checkpoint_param = OpenApiParameter(
    name="checkpoint",
    type=str,
    location=OpenApiParameter.QUERY,
    required=False,
    description="Selected checkpoint UUID. Defaults to the first active checkpoint.",
)

_comparison_checkpoint_param = OpenApiParameter(
    name="comparison_checkpoint",
    type=str,
    location=OpenApiParameter.QUERY,
    required=False,
    description=(
        "Comparison checkpoint UUID for district return/darpeeth comparison. "
        "Defaults to a different active checkpoint when available."
    ),
)

_quarter_param = OpenApiParameter(
    name="quarter",
    type=int,
    location=OpenApiParameter.QUERY,
    required=False,
    description="Fiscal quarter number: 1..4. Defaults to 1.",
)

_search_param = OpenApiParameter(
    name="search",
    type=str,
    location=OpenApiParameter.QUERY,
    required=False,
    description="Search commodity/unit text within movement tables.",
)

_top_param = OpenApiParameter(
    name="top",
    type=int,
    location=OpenApiParameter.QUERY,
    required=False,
    description="Top N districts for comparison. Defaults to 8.",
)

_volume_limit_param = OpenApiParameter(
    name="volume_limit",
    type=int,
    location=OpenApiParameter.QUERY,
    required=False,
    description="Max rows in movement volume section. Defaults to 10.",
)

_export_format_param = OpenApiParameter(
    name="export_format",
    type=str,
    location=OpenApiParameter.QUERY,
    required=True,
    description="Export format: print, excel, pdf.",
)


def _parse_int_query(request, field_name, default, minimum=1, maximum=100):
    raw_value = request.query_params.get(field_name)
    if raw_value is None or str(raw_value).strip() == "":
        return default

    try:
        parsed = int(str(raw_value).strip())
    except (TypeError, ValueError):
        raise ValidationError({field_name: f"Invalid integer value: {raw_value}."})

    if parsed < minimum or parsed > maximum:
        raise ValidationError(
            {field_name: f"Value must be between {minimum} and {maximum}."}
        )
    return parsed


def _active_checkpoints_queryset():
    return CheckPoint.objects.filter(is_active=True).order_by("name", "location")


def _resolve_checkpoint_from_query(raw_value, field_name, fallback=None):
    if raw_value is None or str(raw_value).strip() == "":
        if fallback:
            return fallback
        raise ValidationError({field_name: "A checkpoint is required."})

    checkpoint = _active_checkpoints_queryset().filter(id=str(raw_value).strip()).first()
    if not checkpoint:
        raise ValidationError({field_name: "Invalid or inactive checkpoint id."})
    return checkpoint


def _quarter_month_entries(quarter):
    months = QUARTER_MONTHS[quarter]
    return [
        {"month_number": month, "month_name": NEPALI_MONTHS[month]["name"]}
        for month in months
    ]


def _movement_base_queryset(
    checkpoint,
    fiscal_year,
    quarter,
    from_bs_date=None,
    to_bs_date=None,
    search_text="",
):
    month_numbers = QUARTER_MONTHS[quarter]
    queryset = ImportSubmission.objects.filter(checkpoint=checkpoint)
    queryset = _fiscal_year_qs(queryset, fiscal_year, prefix="import_nepali")
    queryset = _apply_bs_date_range_filter(
        queryset, from_bs_date, to_bs_date, prefix="import_nepali"
    )
    queryset = queryset.filter(import_nepali_month__in=month_numbers)

    if search_text:
        queryset = queryset.filter(
            Q(commodity_type__name__icontains=search_text)
            | Q(unit_of_measurement__name__icontains=search_text)
        )
    return queryset


def _checkpoint_period_queryset(
    model_class,
    checkpoint,
    fiscal_year,
    quarter,
    date_prefix,
    from_bs_date=None,
    to_bs_date=None,
):
    queryset = model_class.objects.filter(checkpoint=checkpoint)
    queryset = _fiscal_year_qs(queryset, fiscal_year, prefix=date_prefix)
    queryset = _apply_bs_date_range_filter(
        queryset, from_bs_date, to_bs_date, prefix=date_prefix
    )
    return queryset.filter(**{f"{date_prefix}_month__in": QUARTER_MONTHS[quarter]})


def _sum_decimal(field_name, filter_query=None):
    sum_kwargs = {}
    if filter_query is not None:
        sum_kwargs["filter"] = filter_query

    return Coalesce(
        Sum(field_name, **sum_kwargs),
        Decimal("0.0"),
        output_field=models.DecimalField(),
    )


def _build_movement_payload(
    checkpoint,
    fiscal_year,
    quarter,
    from_bs_date=None,
    to_bs_date=None,
    search_text="",
    unit_normalizer=None,
):
    month_entries = _quarter_month_entries(quarter)
    month_number_to_name = {
        entry["month_number"]: entry["month_name"] for entry in month_entries
    }
    month_name_totals = {
        entry["month_name"]: Decimal("0.0") for entry in month_entries
    }

    queryset = _movement_base_queryset(
        checkpoint=checkpoint,
        fiscal_year=fiscal_year,
        quarter=quarter,
        from_bs_date=from_bs_date,
        to_bs_date=to_bs_date,
        search_text=search_text,
    )

    if unit_normalizer is None:
        unit_normalizer = UnitConversionNormalizer()

    raw_rows = (
        queryset.values(
            "commodity_type__name",
            "unit_of_measurement_id",
            "unit_of_measurement__name",
            "import_nepali_month",
        )
        .annotate(
            total_quantity=Coalesce(
                Sum("total_quantity"),
                Decimal("0.0"),
                output_field=models.DecimalField(),
            )
        )
        .order_by("commodity_type__name", "import_nepali_month")
    )

    row_map = {}
    for entry in raw_rows:
        commodity_name = entry["commodity_type__name"] or "Unknown"
        normalized_quantity, normalized_unit_name = unit_normalizer.normalize_quantity(
            entry["total_quantity"],
            entry["unit_of_measurement_id"],
            fallback_unit_name=entry["unit_of_measurement__name"] or "",
        )
        row_key = (commodity_name, normalized_unit_name)
        month_name = month_number_to_name.get(entry["import_nepali_month"])
        if not month_name:
            continue

        if row_key not in row_map:
            row_map[row_key] = {
                "commodity": commodity_name,
                "unit": normalized_unit_name,
                "monthly_quantities": {
                    month["month_name"]: Decimal("0.0") for month in month_entries
                },
                "quarter_total": Decimal("0.0"),
            }

        row_map[row_key]["monthly_quantities"][month_name] += normalized_quantity
        row_map[row_key]["quarter_total"] += normalized_quantity
        month_name_totals[month_name] += normalized_quantity

    rows = sorted(row_map.values(), key=lambda item: item["quarter_total"], reverse=True)
    quarter_total = sum(month_name_totals.values(), Decimal("0.0"))

    return {
        "rows": rows,
        "month_entries": month_entries,
        "totals": {
            "monthly_quantities": month_name_totals,
            "quarter_total": quarter_total,
        },
    }


def _build_health_inspection_payload(
    checkpoint,
    fiscal_year,
    quarter,
    from_bs_date=None,
    to_bs_date=None,
    unit_normalizer=None,
):
    if unit_normalizer is None:
        unit_normalizer = UnitConversionNormalizer()

    queryset = _checkpoint_period_queryset(
        HealthInspectionSubmission,
        checkpoint,
        fiscal_year,
        quarter,
        "health_nepali",
        from_bs_date=from_bs_date,
        to_bs_date=to_bs_date,
    )
    raw_rows = (
        queryset.values(
            "product_name",
            "unit_of_measurement_id",
            "unit_of_measurement__name",
        )
        .annotate(
            passed=_sum_decimal("quantity", Q(result__iexact="Pass")),
            failed=_sum_decimal("quantity", Q(result__iexact="Fail")),
            total_quantity=_sum_decimal("quantity"),
        )
        .order_by("product_name", "unit_of_measurement__name")
    )

    row_map = {}
    for entry in raw_rows:
        product_name = entry["product_name"] or "Unknown"
        unit_id = entry["unit_of_measurement_id"]
        fallback_unit_name = entry["unit_of_measurement__name"] or ""
        passed, normalized_unit_name = unit_normalizer.normalize_quantity(
            entry["passed"], unit_id, fallback_unit_name=fallback_unit_name
        )
        failed, _ = unit_normalizer.normalize_quantity(
            entry["failed"], unit_id, fallback_unit_name=fallback_unit_name
        )
        total_quantity, _ = unit_normalizer.normalize_quantity(
            entry["total_quantity"], unit_id, fallback_unit_name=fallback_unit_name
        )

        row_key = (product_name, normalized_unit_name)
        if row_key not in row_map:
            row_map[row_key] = {
                "product": product_name,
                "unit": normalized_unit_name,
                "passed": Decimal("0.0"),
                "failed": Decimal("0.0"),
                "total_quantity": Decimal("0.0"),
            }

        row_map[row_key]["passed"] += passed
        row_map[row_key]["failed"] += failed
        row_map[row_key]["total_quantity"] += total_quantity

    rows = sorted(
        row_map.values(),
        key=lambda item: (item["product"] or "", item["unit"] or ""),
    )
    return {
        "title": "Health Inspection Summary",
        "rows": rows,
    }


def _build_destruction_payload(
    checkpoint,
    fiscal_year,
    quarter,
    from_bs_date=None,
    to_bs_date=None,
    unit_normalizer=None,
):
    if unit_normalizer is None:
        unit_normalizer = UnitConversionNormalizer()

    queryset = _checkpoint_period_queryset(
        DestructionSubmission,
        checkpoint,
        fiscal_year,
        quarter,
        "destruction_nepali",
        from_bs_date=from_bs_date,
        to_bs_date=to_bs_date,
    )
    raw_rows = (
        queryset.values(
            "commodity_type__name",
            "destruction_method",
            "unit_of_measurement_id",
            "unit_of_measurement__name",
        )
        .annotate(total_quantity=_sum_decimal("quantity"))
        .order_by(
            "commodity_type__name",
            "destruction_method",
            "unit_of_measurement__name",
        )
    )

    row_map = {}
    for entry in raw_rows:
        commodity_name = entry["commodity_type__name"] or "Unknown"
        method = entry["destruction_method"] or "Unknown"
        total_quantity, normalized_unit_name = unit_normalizer.normalize_quantity(
            entry["total_quantity"],
            entry["unit_of_measurement_id"],
            fallback_unit_name=entry["unit_of_measurement__name"] or "",
        )

        row_key = (commodity_name, method, normalized_unit_name)
        if row_key not in row_map:
            row_map[row_key] = {
                "commodity": commodity_name,
                "method": method,
                "unit": normalized_unit_name,
                "total_quantity": Decimal("0.0"),
            }

        row_map[row_key]["total_quantity"] += total_quantity

    rows = sorted(
        row_map.values(),
        key=lambda item: (
            item["commodity"] or "",
            item["method"] or "",
            item["unit"] or "",
        ),
    )
    return {
        "title": "Destruction / Disposal Log",
        "rows": rows,
    }


def _build_revenue_payload(
    checkpoint,
    fiscal_year,
    quarter,
    from_bs_date=None,
    to_bs_date=None,
):
    queryset = _checkpoint_period_queryset(
        RevenueFineSubmission,
        checkpoint,
        fiscal_year,
        quarter,
        "revenue_nepali",
        from_bs_date=from_bs_date,
        to_bs_date=to_bs_date,
    )
    raw_rows = (
        queryset.values("collection_type__name", "currency")
        .annotate(amount=_sum_decimal("base_amount"))
        .order_by("collection_type__name", "currency")
    )
    total_amount = queryset.aggregate(total=_sum_decimal("amount_in_npr"))["total"]

    return {
        "title": "Revenue Collection Summary",
        "total_amount": total_amount,
        "rows": [
            {
                "category": entry["collection_type__name"] or "Unknown",
                "currency": entry["currency"] or "NPR",
                "amount": entry["amount"],
            }
            for entry in raw_rows
        ],
    }


def _extract_district(address_value):
    if not address_value:
        return "Unknown"

    text = " ".join(str(address_value).replace("\n", " ").split()).strip()
    if not text:
        return "Unknown"

    first_segment = re.split(r"[,;/|]", text, maxsplit=1)[0].strip()
    first_segment = re.sub(r"\bward\b.*$", "", first_segment, flags=re.IGNORECASE).strip()
    first_segment = re.sub(r"\d+", "", first_segment).strip(" -")
    if not first_segment:
        return "Unknown"
    return first_segment[:80].title()


def _zero_district_row():
    return {"buffalo": Decimal("0.0"), "goat": Decimal("0.0"), "total": Decimal("0.0")}


def _district_checks_map(
    checkpoint,
    fiscal_year,
    quarter,
    from_bs_date=None,
    to_bs_date=None,
    unit_normalizer=None,
):
    if unit_normalizer is None:
        unit_normalizer = UnitConversionNormalizer()

    queryset = _movement_base_queryset(
        checkpoint=checkpoint,
        fiscal_year=fiscal_year,
        quarter=quarter,
        from_bs_date=from_bs_date,
        to_bs_date=to_bs_date,
        search_text="",
    )

    aggregated = (
        queryset.values(
            "importer_address",
            "commodity_type__name",
            "unit_of_measurement_id",
            "unit_of_measurement__name",
        )
        .annotate(
            total_quantity=Coalesce(
                Sum("total_quantity"),
                Decimal("0.0"),
                output_field=models.DecimalField(),
            )
        )
        .order_by()
    )

    district_map = defaultdict(_zero_district_row)
    for entry in aggregated:
        commodity_name = (entry["commodity_type__name"] or "").lower()
        quantity, _ = unit_normalizer.normalize_quantity(
            entry["total_quantity"],
            entry["unit_of_measurement_id"],
            fallback_unit_name=entry["unit_of_measurement__name"] or "",
        )
        district = _extract_district(entry["importer_address"])

        matched = False
        if any(keyword in commodity_name for keyword in BUFFALO_KEYWORDS):
            district_map[district]["buffalo"] += quantity
            matched = True
        if any(keyword in commodity_name for keyword in GOAT_KEYWORDS):
            district_map[district]["goat"] += quantity
            matched = True

        if matched:
            district_map[district]["total"] += quantity

    return district_map


def _district_comparison_rows(
    selected_checkpoint,
    comparison_checkpoint,
    fiscal_year,
    quarter,
    top_limit,
    from_bs_date=None,
    to_bs_date=None,
    unit_normalizer=None,
):
    selected_map = _district_checks_map(
        selected_checkpoint,
        fiscal_year,
        quarter,
        from_bs_date=from_bs_date,
        to_bs_date=to_bs_date,
        unit_normalizer=unit_normalizer,
    )
    comparison_map = _district_checks_map(
        comparison_checkpoint,
        fiscal_year,
        quarter,
        from_bs_date=from_bs_date,
        to_bs_date=to_bs_date,
        unit_normalizer=unit_normalizer,
    )

    rows = []
    all_districts = set(selected_map.keys()) | set(comparison_map.keys())
    for district in all_districts:
        selected = selected_map.get(district, _zero_district_row())
        comparison = comparison_map.get(district, _zero_district_row())
        combined_total = selected["total"] + comparison["total"]
        if combined_total == Decimal("0.0"):
            continue

        rows.append(
            {
                "district": district,
                "selected_checkpoint": {
                    "buffalo": selected["buffalo"],
                    "goat": selected["goat"],
                },
                "comparison_checkpoint": {
                    "buffalo": comparison["buffalo"],
                    "goat": comparison["goat"],
                },
                "combined_total": combined_total,
            }
        )

    rows.sort(key=lambda row: row["combined_total"], reverse=True)
    return rows[:top_limit]


def _movement_to_monthly_data(movement_payload):
    month_entries = movement_payload["month_entries"]
    rows = movement_payload["rows"]
    monthly_data = []

    for month_entry in month_entries:
        month_name = month_entry["month_name"]
        month_items = []
        for row in rows:
            quantity = row["monthly_quantities"][month_name]
            if quantity == Decimal("0.0"):
                continue
            month_items.append(
                {
                    "commodity": row["commodity"],
                    "unit": row["unit"],
                    "total_quantity": quantity,
                }
            )

        monthly_data.append(
            {
                "nepali_month": month_entry["month_number"],
                "month_name": month_name,
                "items": month_items,
            }
        )
    return monthly_data


def _safe_file_token(raw_value):
    token = re.sub(r"[^a-zA-Z0-9_-]+", "_", str(raw_value).strip()).strip("_")
    return (token or "checkpoint").lower()


@extend_schema(
    tags=["Admin Reports"],
    summary="Admin checkpost movement and enforcement overview",
    description=(
        "Returns quarter-wise checkpost movement, health inspection, destruction, "
        "revenue, movement volume, and district return/darpeeth comparison data "
        "for admin dashboard usage."
    ),
    parameters=[
        _fiscal_year_param,
        _year_param,
        _from_bs_date_param,
        _to_bs_date_param,
        _checkpoint_param,
        _comparison_checkpoint_param,
        _quarter_param,
        _search_param,
        _top_param,
        _volume_limit_param,
    ],
    responses={200: OpenApiResponse(description="Overview payload for admin report page.")},
)
class AdminCheckpostOverviewAPIView(APIView):
    permission_classes = [IsAuthenticated, IsAdminUserRole]

    def get(self, request, *args, **kwargs):
        fiscal_year = _get_nepali_year(request)
        from_bs_date, to_bs_date = _get_bs_date_range(request)
        quarter = _parse_int_query(request, "quarter", default=1, minimum=1, maximum=4)
        top_limit = _parse_int_query(request, "top", default=8, minimum=1, maximum=50)
        volume_limit = _parse_int_query(
            request, "volume_limit", default=10, minimum=1, maximum=100
        )
        search_text = (request.query_params.get("search") or "").strip()

        checkpoints = list(_active_checkpoints_queryset())
        if not checkpoints:
            raise ValidationError(
                {"checkpoint": "No active checkpoints are configured."}
            )

        selected_checkpoint = _resolve_checkpoint_from_query(
            request.query_params.get("checkpoint"),
            field_name="checkpoint",
            fallback=checkpoints[0],
        )

        comparison_fallback = next(
            (item for item in checkpoints if item.id != selected_checkpoint.id),
            selected_checkpoint,
        )
        comparison_checkpoint = _resolve_checkpoint_from_query(
            request.query_params.get("comparison_checkpoint"),
            field_name="comparison_checkpoint",
            fallback=comparison_fallback,
        )
        unit_normalizer = UnitConversionNormalizer()

        movement_payload = _build_movement_payload(
            checkpoint=selected_checkpoint,
            fiscal_year=fiscal_year,
            quarter=quarter,
            from_bs_date=from_bs_date,
            to_bs_date=to_bs_date,
            search_text=search_text,
            unit_normalizer=unit_normalizer,
        )
        health_inspection_data = _build_health_inspection_payload(
            checkpoint=selected_checkpoint,
            fiscal_year=fiscal_year,
            quarter=quarter,
            from_bs_date=from_bs_date,
            to_bs_date=to_bs_date,
            unit_normalizer=unit_normalizer,
        )
        destruction_data = _build_destruction_payload(
            checkpoint=selected_checkpoint,
            fiscal_year=fiscal_year,
            quarter=quarter,
            from_bs_date=from_bs_date,
            to_bs_date=to_bs_date,
            unit_normalizer=unit_normalizer,
        )
        revenue_data = _build_revenue_payload(
            checkpoint=selected_checkpoint,
            fiscal_year=fiscal_year,
            quarter=quarter,
            from_bs_date=from_bs_date,
            to_bs_date=to_bs_date,
        )
        movement_rows = movement_payload["rows"]
        district_rows = _district_comparison_rows(
            selected_checkpoint=selected_checkpoint,
            comparison_checkpoint=comparison_checkpoint,
            fiscal_year=fiscal_year,
            quarter=quarter,
            top_limit=top_limit,
            from_bs_date=from_bs_date,
            to_bs_date=to_bs_date,
            unit_normalizer=unit_normalizer,
        )

        fiscal_year_label = _fiscal_year_label(fiscal_year)
        quarter_short_label = f"Q{quarter}"
        quarter_label = QUARTER_LABELS[quarter]

        return Response(
            {
                "fiscal_year": fiscal_year_label,
                "quarter": {
                    "number": quarter,
                    "label": quarter_label,
                    "months": movement_payload["month_entries"],
                },
                "search": search_text,
                "health_inspection_data": health_inspection_data,
                "destruction_data": destruction_data,
                "revenue_data": revenue_data,
                "official_data_label": (
                    f"OFFICIAL DATA {quarter_short_label} {fiscal_year_label}"
                ),
                "available_checkpoints": [
                    {
                        "id": checkpoint.id,
                        "name": checkpoint.name,
                        "location": checkpoint.location,
                    }
                    for checkpoint in checkpoints
                ],
                "selected_checkpoint": {
                    "id": selected_checkpoint.id,
                    "name": selected_checkpoint.name,
                    "location": selected_checkpoint.location,
                },
                "comparison_checkpoint": {
                    "id": comparison_checkpoint.id,
                    "name": comparison_checkpoint.name,
                    "location": comparison_checkpoint.location,
                },
                "movement_data": {
                    "title": f"{selected_checkpoint.name} Movement Data",
                    "month_headers": [
                        month["month_name"] for month in movement_payload["month_entries"]
                    ],
                    "rows": movement_rows,
                    "totals": movement_payload["totals"],
                },
                "movement_volume": {
                    "title": (
                        f"{selected_checkpoint.name} "
                        f"{quarter_short_label} Movement Volume"
                    ),
                    "rows": movement_rows[:volume_limit],
                },
                "district_return_comparison": {
                    "title": (
                        f"District-wise Returns/Darpeeth Comparison "
                        f"({quarter_short_label} Top {top_limit})"
                    ),
                    "selected_checkpoint_name": selected_checkpoint.name,
                    "comparison_checkpoint_name": comparison_checkpoint.name,
                    "rows": district_rows,
                },
            }
        )


@extend_schema(
    tags=["Admin Reports"],
    summary="Export admin checkpost movement report",
    description=(
        "Exports selected checkpoint quarter movement table in print HTML, CSV, or PDF."
    ),
    parameters=[
        _export_format_param,
        _fiscal_year_param,
        _year_param,
        _from_bs_date_param,
        _to_bs_date_param,
        _checkpoint_param,
        _quarter_param,
        _search_param,
    ],
    responses={200: OpenApiResponse(description="Export file response.")},
)
class AdminCheckpostExportAPIView(APIView):
    permission_classes = [IsAuthenticated, IsAdminUserRole]

    def get(self, request, *args, **kwargs):
        export_format = (request.query_params.get("export_format") or "").strip().lower()
        if export_format not in {"print", "excel", "pdf"}:
            raise ValidationError(
                {"export_format": "Invalid format. Use one of: print, excel, pdf."}
            )

        fiscal_year = _get_nepali_year(request)
        from_bs_date, to_bs_date = _get_bs_date_range(request)
        quarter = _parse_int_query(request, "quarter", default=1, minimum=1, maximum=4)
        search_text = (request.query_params.get("search") or "").strip()

        fallback_checkpoint = _active_checkpoints_queryset().first()
        if not fallback_checkpoint:
            raise ValidationError(
                {"checkpoint": "No active checkpoints are configured."}
            )
        selected_checkpoint = _resolve_checkpoint_from_query(
            request.query_params.get("checkpoint"),
            field_name="checkpoint",
            fallback=fallback_checkpoint,
        )

        movement_payload = _build_movement_payload(
            checkpoint=selected_checkpoint,
            fiscal_year=fiscal_year,
            quarter=quarter,
            from_bs_date=from_bs_date,
            to_bs_date=to_bs_date,
            search_text=search_text,
            unit_normalizer=UnitConversionNormalizer(),
        )
        monthly_data = _movement_to_monthly_data(movement_payload)

        fiscal_year_label = _fiscal_year_label(fiscal_year)
        quarter_label = f"Q{quarter}"
        report_title = f"{selected_checkpoint.name} {quarter_label} Movement Data"
        filename_base = (
            f"admin_checkpost_{_safe_file_token(selected_checkpoint.name)}_"
            f"{fiscal_year}_{quarter_label.lower()}"
        )

        if export_format == "excel":
            csv_content = _monthly_data_to_csv(report_title, fiscal_year_label, monthly_data)
            response = HttpResponse(csv_content, content_type="text/csv; charset=utf-8")
            response["Content-Disposition"] = f'attachment; filename="{filename_base}.csv"'
            return response

        if export_format == "pdf":
            pdf_content = _monthly_data_to_pdf_bytes(report_title, fiscal_year_label, monthly_data)
            response = HttpResponse(pdf_content, content_type="application/pdf")
            response["Content-Disposition"] = f'attachment; filename="{filename_base}.pdf"'
            return response

        html_content = _monthly_data_to_print_html(report_title, fiscal_year_label, monthly_data)
        response = HttpResponse(html_content, content_type="text/html; charset=utf-8")
        response["Content-Disposition"] = f'inline; filename="{filename_base}.html"'
        return response
