import logging

from django.conf import settings
from django.http import Http404
from rest_framework import authentication, mixins, serializers
from rest_framework.authentication import get_authorization_header
from rest_framework.exceptions import AuthenticationFailed
from rest_framework.generics import GenericAPIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from basic_info import models as basic_models
from flower.viewsets import LimitedLimitOffsetPagination
from mes import models as mes_models
from printing.models import PrintingJob
from shipment.models import SalesItem, Shipment

logger = logging.getLogger(__name__)


class AgentAccessPrincipal:
    id = None
    username = "agent"
    is_staff = False
    is_superuser = False
    is_anonymous = False
    is_authenticated = True


class AgentAccessKeyAuthentication(authentication.BaseAuthentication):
    """
    使用固定 AGENT_ACCESS_KEY 的轻量认证。

    约定：
    - 通过 Authorization 头直接传入密钥
    - 不使用 Bearer 前缀
    """

    def authenticate(self, request):
        configured_key = str(getattr(settings, "AGENT_ACCESS_KEY", "") or "").strip()
        if not configured_key:
            logger.warning("Agent API authentication failed: AGENT_ACCESS_KEY is not configured")
            raise AuthenticationFailed("AGENT_ACCESS_KEY 未配置")

        provided_key = get_authorization_header(request).decode("utf-8").strip()
        if not provided_key:
            raise AuthenticationFailed("缺少 Authorization 请求头")

        if provided_key != configured_key:
            raise AuthenticationFailed("AGENT_ACCESS_KEY 无效")

        return AgentAccessPrincipal(), None

    def authenticate_header(self, request):
        return "AgentAccessKey"


class AgentUnshippedShipmentQuerySerializer(serializers.Serializer):
    merchant_id = serializers.IntegerField(min_value=1)
    area = serializers.CharField(allow_blank=False, max_length=30)
    limit = serializers.IntegerField(required=False, min_value=1)
    offset = serializers.IntegerField(required=False, min_value=0)

    def validate(self, attrs):
        area = attrs["area"].strip()
        if not area:
            raise serializers.ValidationError({"area": "地区不能为空"})

        merchant = basic_models.Merchant.objects.filter(id=attrs["merchant_id"]).first()
        if merchant is None:
            raise serializers.ValidationError({"merchant_id": "商户不存在"})

        attrs["area"] = area
        attrs["merchant"] = merchant
        return attrs


class AgentSalesItemSerializer(serializers.ModelSerializer):
    unit_display = serializers.CharField(source="get_unit_display", read_only=True)
    printing_job_width = serializers.SerializerMethodField()

    class Meta:
        model = SalesItem
        fields = [
            "id",
            "name",
            "quantity",
            "unit",
            "unit_display",
            "position",
            "remark",
            "printing_job_id",
            "printing_job_width",
        ]

    def get_printing_job_width(self, obj):
        width_map = self.context.get("printing_job_width_map", {})
        return width_map.get(obj.printing_job_id)


class AgentShipmentListSerializer(serializers.ModelSerializer):
    customer_name = serializers.CharField(source="customer.name", read_only=True)
    status_display = serializers.CharField(source="get_status_display", read_only=True)
    fabric = serializers.SerializerMethodField()
    order_description = serializers.SerializerMethodField()
    delivery_id = serializers.IntegerField(read_only=True, allow_null=True)
    sales_items = serializers.SerializerMethodField()

    class Meta:
        model = Shipment
        fields = [
            "id",
            "merchant_id",
            "customer",
            "customer_name",
            "fabric",
            "order_description",
            "shipment_date",
            "address",
            "contact_name",
            "contact_phone",
            "area",
            "remark",
            "status",
            "status_display",
            "external_id",
            "geo_coordinates",
            "delivery_id",
            "delivery",
            "sales_items",
            "created_at",
            "updated_at",
        ]

    def get_fabric(self, obj):
        rel = getattr(obj, "items", None)
        if rel is None:
            return None

        first_item = next((item for item in obj.items.all() if item.delete_at is None), None)
        if first_item is None or not first_item.printing_job_id:
            return None

        from printing.models import PrintingJob

        printing_job = (
            PrintingJob.objects.filter(id=first_item.printing_job_id)
            .select_related("printing_order")
            .first()
        )
        if printing_job is None or printing_job.printing_order is None:
            return None
        return printing_job.printing_order.fabric

    def get_order_description(self, obj):
        rel = getattr(obj, "items", None)
        if rel is None:
            return None

        first_item = next((item for item in obj.items.all() if item.delete_at is None), None)
        if first_item is None or not first_item.printing_job_id:
            return None

        from printing.models import PrintingJob

        printing_job = (
            PrintingJob.objects.filter(id=first_item.printing_job_id)
            .select_related("printing_order")
            .first()
        )
        if printing_job is None or printing_job.printing_order is None:
            return None
        return printing_job.printing_order.rolling_warn

    def get_sales_items(self, obj):
        items = [i for i in obj.items.all() if i.delete_at is None]
        return AgentSalesItemSerializer(items, many=True, context=self.context).data


class AgentUnshippedShipmentListView(mixins.ListModelMixin, GenericAPIView):
    """
    Agent 专用：查询尚未进入送货单的出货单列表。

    GET /api/v2/ai/shipments/unshipped/?merchant_id=<id>&area=<地区>&limit=<n>&offset=<n>
    """

    authentication_classes = [AgentAccessKeyAuthentication]
    permission_classes = [IsAuthenticated]
    serializer_class = AgentShipmentListSerializer
    pagination_class = LimitedLimitOffsetPagination

    def get(self, request):
        query_serializer = AgentUnshippedShipmentQuerySerializer(data=request.query_params)
        query_serializer.is_valid(raise_exception=True)
        self.validated_query = query_serializer.validated_data
        return self.list(request)

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        page = self.paginate_queryset(queryset)
        shipments = page if page is not None else queryset

        # Batch-fetch printing job widths to avoid N+1
        pj_ids = {
            item.printing_job_id
            for shipment in shipments
            for item in shipment.items.all()
            if item.printing_job_id and item.delete_at is None
        }
        width_map = {}
        if pj_ids:
            width_map = {
                job.id: job.printing_order.width
                for job in PrintingJob.objects.filter(id__in=pj_ids).select_related("printing_order")
            }

        ctx = {**self.get_serializer_context(), "printing_job_width_map": width_map}
        serializer = self.get_serializer(shipments, many=True, context=ctx)
        if page is not None:
            return self.get_paginated_response(serializer.data)
        return Response(serializer.data)

    def get_queryset(self):
        validated_query = getattr(self, "validated_query", None)
        if validated_query is None:
            query_serializer = AgentUnshippedShipmentQuerySerializer(data=self.request.query_params)
            query_serializer.is_valid(raise_exception=True)
            validated_query = query_serializer.validated_data

        merchant = validated_query["merchant"]
        area = validated_query["area"]

        return (
            Shipment.objects.filter(
                merchant=merchant,
                area=area,
                delivery__isnull=True,
            )
            .select_related("customer", "merchant")
            .prefetch_related("items")
            .order_by("-created_at", "-id")
        )


# ---------------------------------------------------------------------------
# Vehicle views
# ---------------------------------------------------------------------------

class AgentMerchantQuerySerializer(serializers.Serializer):
    """Base serializer that validates merchant_id and returns merchant instance."""

    merchant_id = serializers.IntegerField(min_value=1)

    def validate_merchant_id(self, value):
        merchant = basic_models.Merchant.objects.filter(id=value).first()
        if merchant is None:
            raise serializers.ValidationError("商户不存在")
        return merchant


class AgentTransportVehicleCapacitySerializer(serializers.ModelSerializer):
    class Meta:
        model = basic_models.TransportVehicleMaterialCapacity
        fields = ["id", "material_name", "capacity"]


class AgentTransportVehicleSerializer(serializers.ModelSerializer):
    material_capacities = AgentTransportVehicleCapacitySerializer(many=True, read_only=True)

    class Meta:
        model = basic_models.TransportVehicle
        fields = ["id", "merchant_id", "name", "license_plate", "material_capacities", "created_at", "updated_at"]


class AgentTransportVehicleListView(mixins.ListModelMixin, GenericAPIView):
    """
    Agent 专用：查询商户下的所有运输车辆及其物料容量。

    GET /api/v2/ai/transport-vehicles/?merchant_id=<id>
    """

    authentication_classes = [AgentAccessKeyAuthentication]
    permission_classes = [IsAuthenticated]
    serializer_class = AgentTransportVehicleSerializer
    pagination_class = LimitedLimitOffsetPagination

    def get(self, request):
        query_serializer = AgentMerchantQuerySerializer(data=request.query_params)
        query_serializer.is_valid(raise_exception=True)
        self.merchant = query_serializer.validated_data["merchant_id"]
        return self.list(request)

    def get_queryset(self):
        merchant = getattr(self, "merchant", None)
        if merchant is None:
            query_serializer = AgentMerchantQuerySerializer(data=self.request.query_params)
            query_serializer.is_valid(raise_exception=True)
            merchant = query_serializer.validated_data["merchant_id"]
        return (
            basic_models.TransportVehicle.objects.filter(merchant=merchant)
            .prefetch_related("material_capacities")
            .order_by("id")
        )


class AgentTransportVehicleDetailView(APIView):
    """
    Agent 专用：通过车牌号查询运输车辆详情。

    GET /api/v2/ai/transport-vehicles/<license_plate>/?merchant_id=<id>

    license_plate 在同一商户内唯一（unique_together: merchant + license_plate）。
    """

    authentication_classes = [AgentAccessKeyAuthentication]
    permission_classes = [IsAuthenticated]

    def get(self, request, license_plate):
        query_serializer = AgentMerchantQuerySerializer(data=request.query_params)
        query_serializer.is_valid(raise_exception=True)
        merchant = query_serializer.validated_data["merchant_id"]

        try:
            vehicle = (
                basic_models.TransportVehicle.objects
                .prefetch_related("material_capacities")
                .get(merchant=merchant, license_plate=license_plate)
            )
        except basic_models.TransportVehicle.DoesNotExist:
            raise Http404

        return Response(AgentTransportVehicleSerializer(vehicle).data)


class AgentMesDeviceCategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = mes_models.DeviceCategory
        fields = ["id", "merchant", "name", "created_at", "updated_at"]


class AgentMesDeviceSerializer(serializers.ModelSerializer):
    category = AgentMesDeviceCategorySerializer(read_only=True)
    capacity_unit_label = serializers.CharField(source='get_capacity_unit_display', read_only=True)

    class Meta:
        model = mes_models.Device
        fields = [
            "id",
            "merchant",
            "category",
            "name",
            "peak_capacity",
            "capacity_unit",
            "capacity_unit_label",
            "extra",
            "created_at",
            "updated_at",
        ]


class AgentMesDeviceListView(mixins.ListModelMixin, GenericAPIView):
    """
    Agent 专用：查询商户下所有 MES 设备，并返回设备分类信息。

    GET /api/v2/ai/mes/devices/?merchant_id=<id>
    """

    authentication_classes = [AgentAccessKeyAuthentication]
    permission_classes = [IsAuthenticated]
    serializer_class = AgentMesDeviceSerializer
    pagination_class = LimitedLimitOffsetPagination

    def get(self, request):
        query_serializer = AgentMerchantQuerySerializer(data=request.query_params)
        query_serializer.is_valid(raise_exception=True)
        self.merchant = query_serializer.validated_data["merchant_id"]
        return self.list(request)

    def get_queryset(self):
        merchant = getattr(self, "merchant", None)
        if merchant is None:
            query_serializer = AgentMerchantQuerySerializer(data=self.request.query_params)
            query_serializer.is_valid(raise_exception=True)
            merchant = query_serializer.validated_data["merchant_id"]
        return mes_models.Device.objects.filter(merchant=merchant).select_related("category").order_by("id")


class AgentMesProductionAssignmentQuerySerializer(AgentMerchantQuerySerializer):
    start_date = serializers.DateField()
    end_date = serializers.DateField()
    device_id = serializers.IntegerField(required=False, min_value=1)
    status = serializers.ChoiceField(required=False, choices=mes_models.ProductionAssignmentStatusEnum.choices)

    def validate(self, attrs):
        attrs = super().validate(attrs)
        if attrs["start_date"] > attrs["end_date"]:
            raise serializers.ValidationError({"end_date": "结束日期不能早于开始日期"})

        merchant = attrs["merchant_id"]
        device_id = attrs.get("device_id")
        if device_id is not None:
            device = mes_models.Device.objects.filter(id=device_id, merchant=merchant).first()
            if device is None:
                raise serializers.ValidationError({"device_id": "设备不存在"})
            attrs["device"] = device
        return attrs


class AgentMesProductionAssignmentEmployeeSerializer(serializers.ModelSerializer):
    class Meta:
        model = basic_models.Employee
        fields = ["id", "name", "merchant_id"]


class AgentMesProductionAssignmentDeviceSerializer(serializers.ModelSerializer):
    category = AgentMesDeviceCategorySerializer(read_only=True)
    capacity_unit_label = serializers.CharField(source='get_capacity_unit_display', read_only=True)

    class Meta:
        model = mes_models.Device
        fields = [
            "id",
            "merchant",
            "category",
            "name",
            "peak_capacity",
            "capacity_unit",
            "capacity_unit_label",
            "extra",
            "created_at",
            "updated_at",
        ]


class AgentMesProductionAssignmentSerializer(serializers.ModelSerializer):
    device = AgentMesProductionAssignmentDeviceSerializer(read_only=True)
    assigner = AgentMesProductionAssignmentEmployeeSerializer(read_only=True)
    assignee = AgentMesProductionAssignmentEmployeeSerializer(read_only=True)
    status_label = serializers.CharField(source='get_status_display', read_only=True)

    class Meta:
        model = mes_models.ProductionAssignment
        fields = [
            "id",
            "merchant",
            "device",
            "content_type",
            "object_id",
            "assigner",
            "assignee",
            "production_quantity",
            "status",
            "status_label",
            "extra",
            "created_at",
            "updated_at",
        ]


class AgentMesProductionAssignmentListView(mixins.ListModelMixin, GenericAPIView):
    """
    Agent 专用：查询指定日期范围内创建的生产安排。

    GET /api/v2/ai/mes/production-assignments/?merchant_id=<id>&start_date=<YYYY-MM-DD>&end_date=<YYYY-MM-DD>
    """

    authentication_classes = [AgentAccessKeyAuthentication]
    permission_classes = [IsAuthenticated]
    serializer_class = AgentMesProductionAssignmentSerializer
    pagination_class = LimitedLimitOffsetPagination

    def get(self, request):
        query_serializer = AgentMesProductionAssignmentQuerySerializer(data=request.query_params)
        query_serializer.is_valid(raise_exception=True)
        self.validated_query = query_serializer.validated_data
        return self.list(request)

    def get_queryset(self):
        validated_query = getattr(self, "validated_query", None)
        if validated_query is None:
            query_serializer = AgentMesProductionAssignmentQuerySerializer(data=self.request.query_params)
            query_serializer.is_valid(raise_exception=True)
            validated_query = query_serializer.validated_data

        merchant = validated_query["merchant_id"]
        queryset = (
            mes_models.ProductionAssignment.objects.filter(
                merchant=merchant,
                created_at__date__gte=validated_query["start_date"],
                created_at__date__lte=validated_query["end_date"],
            )
            .select_related("device", "device__category", "assigner", "assignee", "content_type")
            .order_by("-created_at", "-id")
        )

        device = validated_query.get("device")
        if device is not None:
            queryset = queryset.filter(device=device)

        status_value = validated_query.get("status")
        if status_value is not None:
            queryset = queryset.filter(status=status_value)

        return queryset
