# retoor <retoor@molodetz.nl>

from __future__ import annotations

import json
import logging
from typing import Any

from devplacepy.database import (
    CUSTOMIZATION_LANGS,
    CUSTOMIZATION_PREF_COLUMNS,
    delete_custom_override,
    get_custom_override,
    get_customization_prefs,
    list_custom_overrides,
    set_custom_override,
    set_customization_pref,
)
from devplacepy.services.devii.errors import ToolInputError

logger = logging.getLogger("devii.customization")

PREVIEW_CHARS = 160


class CustomizationController:
    def __init__(self, owner_kind: str, owner_id: str) -> None:
        self._owner_kind = owner_kind
        self._owner_id = owner_id

    async def dispatch(self, name: str, arguments: dict[str, Any]) -> str:
        if name == "customize_list":
            return self._list()
        if name == "customize_get":
            return self._get(arguments)
        if name == "customize_set_css":
            return self._set(arguments, "css", "css")
        if name == "customize_set_js":
            return self._set(arguments, "js", "js")
        if name == "customize_reset":
            return self._reset(arguments)
        if name == "customize_set_enabled":
            return self._set_enabled(arguments)
        raise ToolInputError(f"Unknown customization tool: {name}")

    def _scope(self, arguments: dict[str, Any]) -> str:
        scope = str(arguments.get("scope", "")).strip()
        if not scope:
            raise ToolInputError(
                "A 'scope' is required: 'global' or a page-type string."
            )
        return scope

    def _lang(self, arguments: dict[str, Any]) -> str | None:
        raw = arguments.get("lang")
        if raw is None or str(raw).strip() == "":
            return None
        lang = str(raw).strip().lower()
        if lang not in CUSTOMIZATION_LANGS:
            raise ToolInputError("'lang' must be 'css' or 'js'.")
        return lang

    def _list(self) -> str:
        rows = list_custom_overrides(self._owner_kind, self._owner_id)
        items = [
            {
                "scope": row.get("scope"),
                "lang": row.get("lang"),
                "enabled": bool(row.get("enabled", 1)),
                "chars": len(row.get("code") or ""),
                "preview": (row.get("code") or "")[:PREVIEW_CHARS],
                "updated_at": row.get("updated_at"),
            }
            for row in rows
        ]
        prefs = get_customization_prefs(self._owner_kind, self._owner_id)
        return json.dumps(
            {
                "status": "success",
                "customizations": items,
                "disabled_global": prefs["disable_global"],
                "disabled_pagetype": prefs["disable_pagetype"],
            },
            ensure_ascii=False,
        )

    def _get(self, arguments: dict[str, Any]) -> str:
        scope = self._scope(arguments)
        lang = self._lang(arguments)
        if lang is None:
            raise ToolInputError("'lang' must be 'css' or 'js'.")
        row = get_custom_override(self._owner_kind, self._owner_id, scope, lang)
        if not row:
            return json.dumps(
                {"status": "success", "scope": scope, "lang": lang, "code": None},
                ensure_ascii=False,
            )
        return json.dumps(
            {
                "status": "success",
                "scope": scope,
                "lang": lang,
                "enabled": bool(row.get("enabled", 1)),
                "code": row.get("code") or "",
            },
            ensure_ascii=False,
        )

    def _set(self, arguments: dict[str, Any], lang: str, code_key: str) -> str:
        scope = self._scope(arguments)
        code = arguments.get(code_key)
        if code is None or str(code).strip() == "":
            raise ToolInputError(f"'{code_key}' code is required.")
        set_custom_override(self._owner_kind, self._owner_id, scope, lang, str(code))
        return json.dumps(
            {
                "status": "success",
                "saved": True,
                "scope": scope,
                "lang": lang,
                "note": "Saved. Call reload_page so the user sees it applied by the server.",
            },
            ensure_ascii=False,
        )

    def _category(self, arguments: dict[str, Any]) -> str:
        category = str(arguments.get("category", "")).strip().lower()
        if category not in CUSTOMIZATION_PREF_COLUMNS:
            raise ToolInputError("'category' must be 'global' or 'pagetype'.")
        return category

    def _enabled(self, arguments: dict[str, Any]) -> bool:
        raw = arguments.get("enabled")
        if isinstance(raw, bool):
            return raw
        return str(raw).strip().lower() in ("true", "1", "yes", "on")

    def _set_enabled(self, arguments: dict[str, Any]) -> str:
        if self._owner_kind != "user":
            raise ToolInputError(
                "Suppressing customizations is only available for signed-in users."
            )
        category = self._category(arguments)
        enabled = self._enabled(arguments)
        set_customization_pref(self._owner_id, category, disabled=not enabled)
        return json.dumps(
            {
                "status": "success",
                "category": category,
                "enabled": enabled,
                "note": "Saved. Call reload_page so the user sees it applied by the server.",
            },
            ensure_ascii=False,
        )

    def _reset(self, arguments: dict[str, Any]) -> str:
        scope = self._scope(arguments)
        lang = self._lang(arguments)
        if scope == "all":
            removed = delete_custom_override(
                self._owner_kind, self._owner_id, scope=None, lang=lang
            )
        else:
            removed = delete_custom_override(
                self._owner_kind, self._owner_id, scope=scope, lang=lang
            )
        return json.dumps(
            {
                "status": "success",
                "removed": removed,
                "scope": scope,
                "lang": lang or "all",
                "note": "Removed. Call reload_page so the user sees the default restored.",
            },
            ensure_ascii=False,
        )
