import json
import logging

from django.http import JsonResponse
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.csrf import csrf_exempt

from .backends import DeviceAuthBackend
from ..conf import devicehub_settings
from ..registry import registry

logger = logging.getLogger("django_devicehub.auth")


@method_decorator(csrf_exempt, name="dispatch")
class BrokerAuthView(View):
    """HTTP authentication endpoint for MQTT brokers.

    Compatible with EMQX HTTP auth backend and Mosquitto auth plugin.

    POST /things/broker/auth/
    Body: {"username": "...", "password": "..."}
    Response: {"result": "allow"} or {"result": "deny"}
    """

    def post(self, request):
        try:
            body = json.loads(request.body)
        except (json.JSONDecodeError, ValueError):
            return JsonResponse({"result": "deny"}, status=400)

        username = body.get("username", "")
        password = body.get("password", "")

        if not username or not password:
            return JsonResponse({"result": "deny"})

        device = DeviceAuthBackend.authenticate(username, password)
        if device is not None:
            device.mark_online()
            return JsonResponse({"result": "allow"})

        return JsonResponse({"result": "deny"})


@method_decorator(csrf_exempt, name="dispatch")
class BrokerACLView(View):
    """ACL endpoint for MQTT brokers — controls per-device topic access.

    Devices can only publish to their own data/status topics
    and subscribe to their own command topic.

    POST /things/broker/acl/
    Body: {"username": "...", "topic": "...", "action": "pub"|"sub"}
    Response: {"result": "allow"} or {"result": "deny"}
    """

    def post(self, request):
        try:
            body = json.loads(request.body)
        except (json.JSONDecodeError, ValueError):
            return JsonResponse({"result": "deny"}, status=400)

        username = body.get("username", "")
        topic = body.get("topic", "")
        action = body.get("action", "")

        if not username or not topic:
            return JsonResponse({"result": "deny"})

        # Find the device across all registered models
        device = None
        device_type_cls = None
        for dt_cls, device_model, _, _ in registry.all_with_models():
            try:
                device = device_model.objects.get(
                    mqtt_username=username,
                    is_active=True,
                )
                device_type_cls = dt_cls
                break
            except device_model.DoesNotExist:
                continue

        if device is None:
            return JsonResponse({"result": "deny"})

        # Build allowed topic list
        prefix = devicehub_settings.TOPIC_PREFIX
        device_id = device.device_id
        type_name = device_type_cls.__name__.lower()

        allowed_topics = [
            f"{prefix}/{type_name}/{device_id}/data",
            f"{prefix}/{type_name}/{device_id}/status",
        ]

        # Devices can subscribe to their command topic
        if action == "sub":
            allowed_topics.append(f"{prefix}/{type_name}/{device_id}/cmd")

        if topic in allowed_topics:
            return JsonResponse({"result": "allow"})

        return JsonResponse({"result": "deny"})
