"""Voice Agents endpoints — a thin, permission-gated proxy to Hunar's Agents API.

Hunar owns agent state; nothing is stored locally, so there is no model, no sync
and no drift. The four operations mirror the Hunar Voice Agents API Docs exactly:
list, retrieve, create, update. The docs expose no delete and no status change,
so neither is offered here.

`HUNAR_API_KEY` never leaves the backend — the browser talks to these endpoints
and only this layer talks to Hunar.
"""

import logging

from rest_framework.permissions import BasePermission
from rest_framework.views import APIView

from core.responses import success_response, error_response

from .agent_serializers import (
    AGENT_STATUSES,
    LANGUAGES,
    VOICE_PERSONAS,
    VoiceAgentCreateSerializer,
    VoiceAgentUpdateSerializer,
)
from .providers.hunar import HunarAPIError, HunarProvider

logger = logging.getLogger(__name__)


class HasVoiceAgentPerm(BasePermission):
    """Gate on the `ai_calls.*_voiceagent` permission for the request's method.

    ADMIN / superusers hold every permission and so pass automatically — the
    same rule every other module in this project uses.
    """

    #: HTTP method -> required permission.
    PERMS = {
        "GET": "ai_calls.view_voiceagent",
        "POST": "ai_calls.add_voiceagent",
        "PUT": "ai_calls.change_voiceagent",
        "PATCH": "ai_calls.change_voiceagent",
        "DELETE": "ai_calls.delete_voiceagent",
    }

    message = "You do not have permission to manage voice agents."

    def has_permission(self, request, view):
        user = request.user
        if not (user and user.is_authenticated):
            return False
        required = self.PERMS.get(request.method)
        if required is None:
            return False
        if user.is_superuser or (getattr(user, "role", "") or "").upper() == "ADMIN":
            return True
        return user.has_perm(required)


def _hunar_error_response(exc: HunarAPIError):
    """Turn a HunarAPIError into our standard error envelope.

    Hunar's own `message`/`details` are passed through so the form can show
    per-field errors (PDF p8-9). 401 is reported as a configuration problem —
    it means OUR key is wrong, which is not the caller's fault.
    """
    status_code = exc.status_code
    message = exc.message
    if status_code == 401:
        status_code = 503
        message = ("The Hunar API rejected our credentials. Check HUNAR_API_KEY "
                   "in the backend environment.")
    elif status_code == 422:
        status_code = 400
    elif status_code not in (400, 404, 502, 503):
        status_code = 502
    return error_response(message, errors={"details": exc.details}, status_code=status_code)


class VoiceAgentListCreateView(APIView):
    """GET  /api/v1/ai-calls/agents/   — paginated list, optional filters
    POST /api/v1/ai-calls/agents/    — create an agent
    """

    permission_classes = [HasVoiceAgentPerm]

    def get(self, request):
        params = request.query_params

        def _enum(name, allowed):
            raw = (params.get(name) or "").strip().upper()
            if not raw or raw == "ALL":
                return None, None
            if raw not in allowed:
                return None, f"Invalid {name}. Allowed: {', '.join(allowed)}."
            return raw, None

        language, err = _enum("language", LANGUAGES)
        if err:
            return error_response(err, status_code=400)
        voice_persona, err = _enum("voice_persona", VOICE_PERSONAS)
        if err:
            return error_response(err, status_code=400)
        status_filter, err = _enum("status", AGENT_STATUSES)
        if err:
            return error_response(err, status_code=400)

        def _int(name, default, lo, hi):
            raw = (params.get(name) or "").strip()
            if not raw.isdigit():
                return default
            return max(lo, min(hi, int(raw)))

        page = _int("page", 1, 1, 10_000)
        page_size = _int("page_size", 20, 1, 100)

        try:
            data = HunarProvider().list_agents(
                language=language, voice_persona=voice_persona, status=status_filter,
                page=page, page_size=page_size,
            )
        except HunarAPIError as exc:
            return _hunar_error_response(exc)

        # Hunar's pagination envelope is passed through unchanged (PDF p7).
        return success_response(data)

    def post(self, request):
        serializer = VoiceAgentCreateSerializer(data=request.data)
        if not serializer.is_valid():
            return error_response("Validation failed.", errors=serializer.errors, status_code=400)
        try:
            agent = HunarProvider().create_agent(serializer.validated_data)
        except HunarAPIError as exc:
            return _hunar_error_response(exc)
        logger.info("[HUNAR] Voice agent created by %s: %s", request.user, agent.get("id"))
        return success_response(agent, "Voice agent created successfully.", status_code=201)


class VoiceAgentDetailView(APIView):
    """GET /api/v1/ai-calls/agents/<agent_id>/  — full detail
    PUT /api/v1/ai-calls/agents/<agent_id>/  — partial update
    """

    permission_classes = [HasVoiceAgentPerm]

    def get(self, request, agent_id):
        try:
            return success_response(HunarProvider().get_agent(agent_id))
        except HunarAPIError as exc:
            return _hunar_error_response(exc)

    def put(self, request, agent_id):
        provider = HunarProvider()
        # Fetch current state first so the persona/language rule can tell a real
        # change from a resubmitted identical value (PDF p6).
        try:
            existing = provider.get_agent(agent_id)
        except HunarAPIError as exc:
            return _hunar_error_response(exc)

        serializer = VoiceAgentUpdateSerializer(
            data=request.data, context={"existing": existing},
        )
        if not serializer.is_valid():
            return error_response("Validation failed.", errors=serializer.errors, status_code=400)
        try:
            agent = provider.update_agent(agent_id, serializer.validated_data)
        except HunarAPIError as exc:
            return _hunar_error_response(exc)
        logger.info("[HUNAR] Voice agent %s updated by %s", agent_id, request.user)
        return success_response(agent, "Voice agent updated successfully.")

    def delete(self, request, agent_id):
        try:
            res = HunarProvider().delete_agent(agent_id)
            logger.info("[HUNAR] Voice agent %s deleted by %s", agent_id, request.user)
            return success_response(res, "Voice agent deleted successfully.")
        except HunarAPIError as exc:
            return _hunar_error_response(exc)


class VoiceAgentOptionsView(APIView):
    """GET /api/v1/ai-calls/agents/options/ — the enums the form and filters need.

    Served from the constants that mirror the PDF so the frontend never hardcodes
    its own copy of the language / persona / status lists.
    """

    permission_classes = [HasVoiceAgentPerm]

    def get(self, request):
        return success_response({
            "languages": LANGUAGES,
            "voice_personas": VOICE_PERSONAS,
            "statuses": AGENT_STATUSES,
        })
