# (c) cavaliba.com  - data/api - conf.py

"""
/api/conf/: read/write Cavaliba configuration (CavalibaConfiguration DB rows).
Gated by p_api_conf (endpoint access) plus p_conf_view/p_conf_admin (read/write
gates, same as the UI configuration page). No business logic here - everything
is delegated to app_home.configuration.

Method inventory: conf.
"""

import json

from django.views.decorators.csrf import csrf_exempt

import app_data.api.helper as helper
from app_data.api.aaa import start_api
from app_home import configuration
from app_home.log import INFO, WARNING, log


@csrf_exempt
def conf(request):
    """GET: export every DB-persisted configuration entry as a flat list.
    POST: upsert a single JSON object or list of objects shaped like GET's
    output (appname/keyname required, value/description/page/order optional).
    Partial failures (e.g. appname="env", missing appname/keyname) are
    reported per-entry in "results" - they don't fail the whole request."""

    aaa_api = start_api(request, permission="p_api_conf")
    if not aaa_api["is_allowed"]:
        return helper.send_denied()

    if request.method == "GET":
        if "p_conf_view" not in aaa_api["perms"] and "p_conf_admin" not in aaa_api["perms"]:
            return helper.send_denied()

        reply = configuration.conf_list_export()

        log(
            INFO,
            aaa=aaa_api,
            app="api",
            view="conf",
            action="GET",
            status="OK",
            data=f"count={len(reply)}",
        )
        return helper.send_response(request, reply, 200)

    if request.method == "POST":
        if "p_conf_admin" not in aaa_api["perms"]:
            return helper.send_denied()

        if aaa_api["is_readonly"]:
            return helper.send_denied("API key is read-only")

        try:
            body = json.loads(request.body.decode("utf-8"))
        except Exception as exc:
            return helper.send_error(f"invalid JSON body: {exc}", 400)

        if isinstance(body, dict):
            entries = [body]
        elif isinstance(body, list):
            entries = body
        else:
            return helper.send_error(
                "invalid JSON body: expected an object or a list of objects", 400
            )

        results = []
        count_ok = 0
        count_ko = 0

        for entry in entries:
            if not isinstance(entry, dict):
                count_ko += 1
                error = f"invalid entry (not an object): {entry!r}"
                results.append({"status": "ko", "error": error})
                log(
                    WARNING,
                    aaa=aaa_api,
                    app="api",
                    view="conf",
                    action="POST",
                    status="KO",
                    data=error,
                )
                continue

            appname = entry.get("appname")
            keyname = entry.get("keyname")

            ok, error = configuration.conf_upsert_entry(
                appname=appname,
                keyname=keyname,
                value=entry.get("value"),
                description=entry.get("description"),
                page=entry.get("page"),
                order=entry.get("order"),
            )

            if ok:
                count_ok += 1
                results.append({"appname": appname, "keyname": keyname, "status": "ok"})
                log(
                    INFO,
                    aaa=aaa_api,
                    app="api",
                    view="conf",
                    action="POST",
                    status="OK",
                    data=f"{appname}.{keyname}",
                )
            else:
                count_ko += 1
                results.append(
                    {"appname": appname, "keyname": keyname, "status": "ko", "error": error}
                )
                log(
                    WARNING,
                    aaa=aaa_api,
                    app="api",
                    view="conf",
                    action="POST",
                    status="KO",
                    data=f"{appname}.{keyname}: {error}",
                )

        if count_ok:
            configuration.refresh_configuration_cache()

        reply = {
            "count": len(entries),
            "count_ok": count_ok,
            "count_ko": count_ko,
            "results": results,
        }
        return helper.send_response(request, reply, 200)

    return helper.send_error("method not allowed", 405)
