"""
Recursive parameter editor – compact multi-column form for config dicts.
Supports: adjustable columns, expand/collapse all, star (pin) important params.
"""
from nicegui import ui
from typing import Dict, Any, List, Set
from pyruns.utils.config_utils import parse_value
from pyruns.ui.theme import INPUT_PROPS

# ── Type → icon / color ──
_TYPE_INFO = {
    "bool":   ("check_circle",  "text-indigo-500",  "bg-indigo-50"),
    "number": ("tag",           "text-blue-500",    "bg-blue-50"),
    "list":   ("data_array",    "text-purple-500",  "bg-purple-50"),
    "string": ("text_fields",   "text-slate-400",   "bg-slate-50"),
}

_TINY = "outlined dense bg-white hide-bottom-space"
# Force Quasar input control to be short
_INPUT_COMPACT = (
    "font-size: 12px; "
    "--q-field-dense-control-height: 24px; "  # shrink control height
)

_EDITOR_CSS_CLIENTS: set = set()

_EDITOR_CSS = """
.param-input .q-field__control { min-height: 26px !important; height: 26px !important; }
.param-input .q-field__marginal { height: 26px !important; }
.param-input .q-field__native { padding: 2px 8px !important; font-size: 12px; }
.param-input input { font-size: 12px !important; }
"""

def _ensure_editor_css():
    """Inject CSS to shrink Quasar input boxes (once per NiceGUI client)."""
    try:
        cid = ui.context.client.id
    except Exception:
        cid = "__default__"
    if cid not in _EDITOR_CSS_CLIENTS:
        _EDITOR_CSS_CLIENTS.add(cid)
        ui.add_css(_EDITOR_CSS)


def _get_type_key(value) -> str:
    if isinstance(value, bool):
        return "bool"
    if isinstance(value, (int, float)):
        return "number"
    if isinstance(value, list):
        return "list"
    return "string"


def recursive_param_editor(
    container,
    data: Dict[str, Any],
    state: Dict[str, Any],
    task_manager,
    columns: int = 2,
    depth: int = 0,
    expansions: List = None,
    starred: Set[str] = None,
    key_prefix: str = "",
    on_star_toggle: Any = None,
) -> None:
    """Build a compact form editor for a (possibly nested) config dict."""
    _ensure_editor_css()

    if expansions is None:
        expansions = []
    if starred is None:
        # Load from persisted settings on first call
        from pyruns.utils.settings import get as _get_setting
        saved = _get_setting("starred_params", [])
        starred = state.setdefault("starred_params", set(saved))

    with container:
        simple_keys = {
            k: v for k, v in data.items()
            if not isinstance(v, dict) and not k.startswith("_meta")
        }
        dict_keys = {k: v for k, v in data.items() if isinstance(v, dict)}

        if simple_keys:
            items = list(simple_keys.items())
            with ui.grid(columns=columns).classes("w-full gap-1"):
                for key, value in items:
                    full_key = f"{key_prefix}{key}" if key_prefix else key
                    _param_cell(data, key, value, full_key, starred, state, on_star_toggle)

        for key, value in dict_keys.items():
            exp = ui.expansion(
                f"{key}", icon="folder_open", value=True,
            ).classes(
                "w-full mt-1 border border-slate-200 "
                "overflow-hidden bg-white"
            ).props(
                "dense header-class='bg-slate-50 text-slate-600 "
                "font-bold tracking-wide text-xs py-0.5'"
            )
            expansions.append(exp)
            with exp:
                with ui.column().classes("w-full px-1 py-1 border-t border-slate-100"):
                    recursive_param_editor(
                        ui.column().classes("w-full gap-0"),
                        value, state, task_manager,
                        columns=columns, depth=depth + 1,
                        expansions=expansions, starred=starred,
                        key_prefix=f"{key_prefix}{key}.",
                        on_star_toggle=on_star_toggle,
                    )


def _param_cell(
    data: dict, key: str, value, full_key: str,
    starred: Set[str], state: Dict[str, Any],
    on_star_toggle: Any = None,
) -> None:
    """Compact param cell with star toggle."""
    tk = _get_type_key(value)
    icon_name, icon_color, icon_bg = _TYPE_INFO[tk]
    is_starred = full_key in starred

    if is_starred:
        card_cls = (
            "w-full border-2 border-amber-300 "
            "px-1.5 py-0.5 transition-all duration-100 gap-0"
        )
        card_bg = "background:#fffbeb"
    else:
        card_cls = (
            "w-full border border-slate-150 "
            "px-1.5 py-0.5 hover:border-indigo-200 hover:shadow-sm "
            "transition-all duration-100 gap-0"
        )
        card_bg = "background:#fafbfc"

    with ui.column().classes(card_cls).style(card_bg):
        # Key row: star btn + type icon + label
        with ui.row().classes("w-full items-center gap-1"):
            def toggle_star(fk=full_key):
                if fk in starred:
                    starred.discard(fk)
                else:
                    starred.add(fk)
                # Persist to _pyruns_.yaml
                from pyruns.utils.settings import save_setting
                save_setting("starred_params", list(starred))
                if on_star_toggle:
                    try:
                        on_star_toggle()
                    except Exception:
                        pass

            star_icon = "star" if is_starred else "star_border"
            star_color = "text-amber-400" if is_starred else "text-slate-300 hover:text-amber-300"
            star_tip = "取消收藏" if is_starred else "收藏此参数"
            ui.button(icon=star_icon, on_click=toggle_star).props(
                "flat dense round size=xs padding=0"
            ).classes(f"{star_color} min-w-0").style(
                "width:18px; height:18px;"
            ).tooltip(star_tip)

            with ui.element("div").classes(
                f"w-4.5 h-4.5 flex items-center justify-center {icon_bg} flex-none"
            ):
                ui.icon(icon_name, size="11px").classes(icon_color)

            ui.label(key).classes(
                "text-xs font-semibold text-slate-600 font-mono truncate leading-none "
                "flex-1 min-w-0"
            ).tooltip(f"{key} ({tk})")

        # Value input — ultra-compact with .param-input CSS class
        def on_change(e, d=data, k=key):
            d[k] = parse_value(e.value)

        if isinstance(value, bool):
            ui.switch(value=value, on_change=on_change).props("dense color=indigo")
        elif isinstance(value, list):
            ui.input(value=str(value), on_change=on_change).props(_TINY).classes(
                "w-full font-mono text-xs text-purple-700 param-input"
            ).tooltip("[1, 2, 3]")
        elif isinstance(value, (int, float)):
            ui.input(value=str(value), on_change=on_change).props(_TINY).classes(
                "w-full font-mono text-xs text-blue-700 param-input"
            )
        else:
            ui.input(value=str(value), on_change=on_change).props(_TINY).classes(
                "w-full font-mono text-xs text-slate-700 param-input"
            )
