"""Authenticated, idempotent endpoint for importing SKEVER WordPress Order Hub orders.

Expected header: X-SKEVER-ORDER-TOKEN
Required environment variable: SKEVER_WORDPRESS_ORDER_TOKEN
"""
import json
import os
import secrets
from decimal import Decimal, InvalidOperation, ROUND_HALF_UP

from django.db import IntegrityError, transaction
from django.http import JsonResponse
from django.utils import timezone
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST

from .models import AuditEvent, Customer, Order, OrderItem

CENT = Decimal("0.01")
MAX_BODY_BYTES = 256 * 1024
MAX_ITEMS = 100


def _error(message, status):
    return JsonResponse({"ok": False, "error": message}, status=status)


def _money(value, field_name):
    try:
        amount = Decimal(str(value)).quantize(CENT, rounding=ROUND_HALF_UP)
    except (InvalidOperation, TypeError, ValueError):
        raise ValueError(f"Invalid {field_name}.")
    if not amount.is_finite() or amount < 0 or amount > Decimal("9999999999.99"):
        raise ValueError(f"Invalid {field_name}.")
    return amount


def _text(value, field_name, limit, required=False):
    if value is None:
        value = ""
    if not isinstance(value, str):
        raise ValueError(f"Invalid {field_name}.")
    value = value.strip()
    if required and not value:
        raise ValueError(f"{field_name} is required.")
    if len(value) > limit:
        raise ValueError(f"{field_name} is too long.")
    return value


def _prepare(payload):
    if not isinstance(payload, dict):
        raise ValueError("Request body must be a JSON object.")
    wp_id = payload.get("order_id")
    if isinstance(wp_id, bool) or not isinstance(wp_id, int) or wp_id < 1:
        raise ValueError("order_id must be a positive integer.")
    wp_number = _text(payload.get("order_number"), "order_number", 64, True)

    customer = payload.get("customer")
    delivery = payload.get("delivery", {})
    items = payload.get("items")
    if not isinstance(customer, dict):
        raise ValueError("customer must be an object.")
    if not isinstance(delivery, dict):
        raise ValueError("delivery must be an object.")
    if not isinstance(items, list) or not items or len(items) > MAX_ITEMS:
        raise ValueError(f"items must contain between 1 and {MAX_ITEMS} entries.")

    customer_data = {
        "name": _text(customer.get("name"), "customer.name", 180, True),
        "phone": _text(customer.get("phone"), "customer.phone", 40, True),
        "email": _text(customer.get("email"), "customer.email", 254),
    }
    delivery_data = {
        "delivery_location": _text(delivery.get("location"), "delivery.location", 500),
        "delivery_building": _text(delivery.get("building"), "delivery.building", 180),
        "delivery_unit": _text(delivery.get("floor_unit"), "delivery.floor_unit", 180),
        "delivery_instructions": _text(delivery.get("instructions"), "delivery.instructions", 2000),
    }
    customer_notes = _text(payload.get("customer_notes"), "customer_notes", 4000)
    prepared_items = []
    total = Decimal("0.00")
    for index, item in enumerate(items, start=1):
        if not isinstance(item, dict):
            raise ValueError(f"Item {index} must be an object.")
        name = _text(item.get("product_name"), f"items[{index}].product_name", 220, True)
        sku = _text(item.get("sku"), f"items[{index}].sku", 80)
        variant = _text(item.get("variant") or item.get("pack"), f"items[{index}].variant", 160)
        try:
            quantity = Decimal(str(item.get("quantity")))
        except (InvalidOperation, TypeError, ValueError):
            raise ValueError(f"Invalid quantity for item {index}.")
        if not quantity.is_finite() or quantity <= 0 or quantity > Decimal("99999999"):
            raise ValueError(f"Invalid quantity for item {index}.")
        quantity = quantity.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
        if quantity <= 0:
            raise ValueError(f"Invalid quantity for item {index}.")
        unit_price = _money(item.get("unit_price", 0), f"unit_price for item {index}")
        line_total = (quantity * unit_price).quantize(CENT, rounding=ROUND_HALF_UP)
        total += line_total
        prepared_items.append({"sku": sku, "product_name": name, "variant": variant,
                               "quantity": quantity, "unit_price": unit_price, "line_total": line_total})
    if total > Decimal("9999999999.99"):
        raise ValueError("Order total is outside the supported range.")

    # Keep the original WP order number as reference, while avoiding collisions with manual portal orders.
    django_number = f"WEB-{wp_number}"
    if len(django_number) > 32:
        django_number = f"WEB-{wp_id}"
    return wp_id, wp_number, django_number, customer_data, delivery_data, customer_notes, prepared_items, total.quantize(CENT)


@csrf_exempt
@require_POST
def receive_website_order(request):
    """Receive a single WordPress order. Does not create invoices, payments or dispatches."""
    expected = os.environ.get("SKEVER_WORDPRESS_ORDER_TOKEN", "").strip()
    supplied = request.headers.get("X-SKEVER-ORDER-TOKEN", "")
    if not expected or not supplied or not secrets.compare_digest(expected, supplied):
        return _error("Unauthorized.", 401)
    if len(request.body) > MAX_BODY_BYTES:
        return _error("Request body is too large.", 413)
    if request.content_type != "application/json":
        return _error("Content-Type must be application/json.", 415)
    try:
        payload = json.loads(request.body.decode("utf-8"))
        (wp_id, wp_number, django_number, customer_data, delivery_data,
         customer_notes, items, total) = _prepare(payload)
    except (UnicodeDecodeError, json.JSONDecodeError):
        return _error("Invalid JSON body.", 400)
    except ValueError as exc:
        return _error(str(exc), 400)

    existing = Order.objects.filter(wordpress_order_id=wp_id).first()
    if existing:
        return JsonResponse({"ok": True, "duplicate": True, "order_id": existing.pk,
                             "order_number": existing.order_number, "status": existing.status}, status=200)

    try:
        with transaction.atomic():
            phone = customer_data["phone"]
            email = customer_data["email"]
            customer = Customer.objects.filter(phone=phone).exclude(phone="").first()
            if customer is None and email:
                customer = Customer.objects.filter(email__iexact=email).exclude(email="").first()
            if customer is None:
                customer = Customer.objects.create(
                    name=customer_data["name"], phone=phone, email=email,
                    delivery_address=delivery_data["delivery_location"], is_active=True,
                )
            else:
                # Do not overwrite an existing customer's name, contact or default address during import.
                changed = False
                if not customer.email and email:
                    customer.email = email
                    changed = True
                if changed:
                    customer.save(update_fields=["email", "updated_at"])

            notes = customer_notes
            order = Order.objects.create(
                order_number=django_number,
                customer=customer,
                status=Order.Status.NEW,
                total_amount=total,
                notes=notes,
                source="website",
                wordpress_order_id=wp_id,
                wordpress_order_number=wp_number,
                delivery_location=delivery_data["delivery_location"],
                delivery_building=delivery_data["delivery_building"],
                delivery_unit=delivery_data["delivery_unit"],
                delivery_instructions=delivery_data["delivery_instructions"],
            )
            OrderItem.objects.bulk_create([OrderItem(order=order, **item) for item in items])
            AuditEvent.objects.create(
                actor=None,
                action="website_order_imported",
                entity_type="Order",
                entity_id=str(order.pk),
                description=f"Imported website order {wp_number} into the portal.",
                metadata={"wordpress_order_id": wp_id, "wordpress_order_number": wp_number,
                          "source": "website", "item_count": len(items), "total_amount": str(total),
                          "received_at": timezone.now().isoformat()},
            )
    except IntegrityError:
        # Idempotency race: the unique WordPress ID is the final duplicate guard.
        existing = Order.objects.filter(wordpress_order_id=wp_id).first()
        if existing:
            return JsonResponse({"ok": True, "duplicate": True, "order_id": existing.pk,
                                 "order_number": existing.order_number, "status": existing.status}, status=200)
        return _error("Could not save order due to a data conflict.", 409)

    return JsonResponse({"ok": True, "duplicate": False, "order_id": order.pk,
                         "order_number": order.order_number, "status": order.status}, status=201)
