"""Settings API views.

Endpoints:
  GET    /api/v1/settings/                                 — list all registered definitions
  GET    /api/v1/settings/<key>/                           — definition + resolved value + overrides
  PUT    /api/v1/settings/<key>/                           — set a value override
  POST   /api/v1/settings/resolve/                         — bulk resolve
  POST   /api/v1/settings/bulk-set/                        — bulk set overrides
  DELETE /api/v1/settings/<key>/overrides/<scope>/<sid>/   — delete an override
"""

from __future__ import annotations

from rest_framework import status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response

from simorgh.apps.app_settings.models import SettingValue
from simorgh.apps.app_settings.registry import SettingsError, get_definition, registered_settings
from simorgh.apps.app_settings.services import invalidate, resolve, set_value

from .serializers import (
    BulkResolveInputSerializer,
    BulkSetInputSerializer,
    SettingDefinitionSerializer,
    SettingOverrideInputSerializer,
    SettingValueSerializer,
)


def _tenant_id(request: Request) -> int | None:
    tenant = getattr(request, "tenant", None)
    if tenant is None:
        return None
    return tenant.pk


def _user_id(request: Request) -> int | None:
    return request.user.pk if request.user.is_authenticated else None


# ---------------------------------------------------------------------------
# Registry discovery
# ---------------------------------------------------------------------------


@api_view(["GET"])
@permission_classes([IsAuthenticated])
def settings_list(request: Request) -> Response:
    """GET /api/v1/settings/

    Returns all registered setting definitions with their resolved values
    for the current tenant/user context.
    """
    tid = _tenant_id(request)
    uid = _user_id(request)
    org_node_id = getattr(request, "org_node_id", None)

    result = []
    for key, definition in registered_settings().items():
        try:
            resolved_value = resolve(
                key, tenant_id=tid, org_node_id=org_node_id, user_id=uid
            )
        except SettingsError:
            resolved_value = definition.default

        overrides = list(
            SettingValue.objects.filter(key=key, tenant_id=tid)
            .order_by("scope", "scope_id")
            .values("id", "scope", "scope_id", "value", "updated_at")
        )

        definition._resolved_value = resolved_value
        definition._overrides = overrides
        result.append(SettingDefinitionSerializer(definition).data)

    return Response(result)


# ---------------------------------------------------------------------------
# Single setting detail (definition + resolved value + overrides)
# ---------------------------------------------------------------------------


@api_view(["GET"])
@permission_classes([IsAuthenticated])
def settings_detail(request: Request, key: str) -> Response:
    """GET /api/v1/settings/<key>/

    Returns the setting definition, its resolved value for the current
    context, and all configured overrides for the current tenant.
    """
    try:
        definition = get_definition(key)
    except SettingsError as exc:
        return Response({"detail": str(exc)}, status=status.HTTP_404_NOT_FOUND)

    tid = _tenant_id(request)
    uid = _user_id(request)
    org_node_id = getattr(request, "org_node_id", None)

    try:
        resolved_value = resolve(
            key, tenant_id=tid, org_node_id=org_node_id, user_id=uid
        )
    except SettingsError:
        resolved_value = definition.default

    overrides = list(
        SettingValue.objects.filter(key=key, tenant_id=tid)
        .order_by("scope", "scope_id")
        .values("id", "scope", "scope_id", "value", "updated_at")
    )

    definition._resolved_value = resolved_value
    definition._overrides = overrides
    return Response(SettingDefinitionSerializer(definition).data)


# ---------------------------------------------------------------------------
# Set a value override
# ---------------------------------------------------------------------------


@api_view(["PUT"])
@permission_classes([IsAuthenticated])
def settings_set(request: Request, key: str) -> Response:
    """PUT /api/v1/settings/<key>/

    Body:
        {
            "scope": "tenant",
            "scope_id": "",
            "value": "new value"
        }

    Creates or updates an override at the given scope.
    """
    input_ser = SettingOverrideInputSerializer(data=request.data)
    if not input_ser.is_valid():
        return Response(input_ser.errors, status=status.HTTP_400_BAD_REQUEST)

    data = input_ser.validated_data
    try:
        obj = set_value(
            key,
            data["value"],
            scope=data["scope"],
            scope_id=data.get("scope_id", ""),
            tenant_id=_tenant_id(request),
            updated_by_id=_user_id(request),
        )
    except SettingsError as exc:
        return Response({"detail": str(exc)}, status=status.HTTP_400_BAD_REQUEST)

    return Response(SettingValueSerializer(obj).data, status=status.HTTP_200_OK)


# ---------------------------------------------------------------------------
# Bulk resolve
# ---------------------------------------------------------------------------


@api_view(["POST"])
@permission_classes([IsAuthenticated])
def settings_bulk_resolve(request: Request) -> Response:
    """POST /api/v1/settings/resolve/

    Body:
        {
            "keys": ["core.preferred_language", "app_settings.max_export_rows"]
        }

    Returns:
        [
            {"key": "...", "type": "string", "resolved_value": "...", "default": "..."},
            ...
        ]

    Unknown keys are silently skipped.
    """
    input_ser = BulkResolveInputSerializer(data=request.data)
    if not input_ser.is_valid():
        return Response(input_ser.errors, status=status.HTTP_400_BAD_REQUEST)

    tid = _tenant_id(request)
    uid = _user_id(request)
    org_node_id = getattr(request, "org_node_id", None)

    result = []
    for key in input_ser.validated_data["keys"]:
        try:
            definition = get_definition(key)
        except SettingsError:
            continue
        try:
            resolved_value = resolve(
                key, tenant_id=tid, org_node_id=org_node_id, user_id=uid
            )
        except SettingsError:
            resolved_value = definition.default
        result.append({
            "key": key,
            "type": definition.type,
            "resolved_value": resolved_value,
            "default": definition.default,
        })

    return Response(result)


# ---------------------------------------------------------------------------
# Bulk set
# ---------------------------------------------------------------------------


@api_view(["POST"])
@permission_classes([IsAuthenticated])
def settings_bulk_set(request: Request) -> Response:
    """POST /api/v1/settings/bulk-set/

    Body:
        {
            "settings": [
                {"key": "core.preferred_language", "scope": "user", "scope_id": "42", "value": "fa"},
                {"key": "core.timezone", "scope": "user", "scope_id": "42", "value": "Asia/Tehran"}
            ]
        }

    Returns:
        {
            "succeeded": [...],
            "failed": [{"key": "...", "scope": "...", "detail": "..."}]
        }
    """
    input_ser = BulkSetInputSerializer(data=request.data)
    if not input_ser.is_valid():
        return Response(input_ser.errors, status=status.HTTP_400_BAD_REQUEST)

    tid = _tenant_id(request)
    uid = _user_id(request)
    succeeded = []
    failed = []

    for item in input_ser.validated_data["settings"]:
        try:
            obj = set_value(
                item["key"],
                item["value"],
                scope=item["scope"],
                scope_id=item.get("scope_id", ""),
                tenant_id=tid,
                updated_by_id=uid,
            )
            succeeded.append(SettingValueSerializer(obj).data)
        except (SettingsError, KeyError) as exc:
            failed.append({
                "key": item.get("key", "?"),
                "scope": item.get("scope", "?"),
                "detail": str(exc),
            })

    return Response({"succeeded": succeeded, "failed": failed})


# ---------------------------------------------------------------------------
# Delete an override
# ---------------------------------------------------------------------------


@api_view(["DELETE"])
@permission_classes([IsAuthenticated])
def settings_delete_override(request: Request, key: str, scope: str, scope_id: str = "") -> Response:
    """DELETE /api/v1/settings/<key>/overrides/<scope>/<scope_id>/

    Deletes an override. After deletion the setting falls back to the next
    most-specific scope. Returns 404 if no override exists for that scope.
    """
    tid = _tenant_id(request)
    deleted, _ = SettingValue.objects.filter(
        key=key, scope=scope, scope_id=scope_id, tenant_id=tid
    ).delete()
    if not deleted:
        return Response(
            {"detail": "No override found for that scope."},
            status=status.HTTP_404_NOT_FOUND,
        )
    invalidate(key)
    return Response(status=status.HTTP_204_NO_CONTENT)
