from __future__ import annotations

from typing import Any

from openclaw_lite.config import save_config, to_dict
from openclaw_lite.schema import ToolContext, ToolSpec
from openclaw_lite.tools.base import fail, ok


def _set_nested(mapping: dict[str, Any], dotted_key: str, value: Any) -> None:
    parts = dotted_key.split(".")
    current = mapping
    for part in parts[:-1]:
        current = current.setdefault(part, {})
    current[parts[-1]] = value


async def runtime_info_tool(context: ToolContext, arguments: dict):
    del arguments
    return ok(
        {
            "session_id": context.session.session_id,
            "provider": context.session.provider_name,
            "model": context.session.model,
            "mode": context.session.mode,
            "paths": {
                "root": str(context.config.paths.root),
                "workspace": str(context.config.paths.workspace),
                "skills": str(context.config.paths.skills),
                "logs": str(context.config.paths.logs),
            },
        }
    )


async def config_get_tool(context: ToolContext, arguments: dict):
    data = to_dict(context.config)
    dotted_key = str(arguments.get("key", "")).strip()
    current: Any = data
    for part in dotted_key.split(".") if dotted_key else []:
        if not isinstance(current, dict) or part not in current:
            return fail(f"config key not found: {dotted_key}")
        current = current[part]
    return ok({"key": dotted_key or "<root>", "value": current})


async def config_set_tool(context: ToolContext, arguments: dict):
    key = str(arguments.get("key", "")).strip()
    value = arguments.get("value")
    if not key:
        return fail("key is required")
    data = to_dict(context.config)
    _set_nested(data, key, value)
    updated = context.runtime.reload_config_from_mapping(data)
    save_config(updated)
    return ok({"key": key, "value": value, "config_file": str(updated.paths.config_file)})


async def set_provider_tool(context: ToolContext, arguments: dict):
    provider_name = str(arguments.get("provider_name", "")).strip()
    if provider_name not in context.runtime.provider_registry.list_names():
        return fail(f"unknown provider: {provider_name}")
    context.session.provider_name = provider_name
    default_model = context.config.default_model_for(provider_name)
    if default_model:
        context.session.model = default_model
    context.runtime.sessions.save(context.session)
    return ok({"provider": context.session.provider_name, "model": context.session.model})


async def set_model_tool(context: ToolContext, arguments: dict):
    model = str(arguments.get("model", "")).strip()
    if not model:
        return fail("model is required")
    context.session.model = model
    context.runtime.sessions.save(context.session)
    return ok({"provider": context.session.provider_name, "model": context.session.model})


async def set_mode_tool(context: ToolContext, arguments: dict):
    mode = str(arguments.get("mode", "")).strip().lower()
    if mode not in {"safe", "yolo", "god"}:
        return fail("mode must be safe, yolo, or god")
    context.session.mode = mode
    context.runtime.sessions.save(context.session)
    return ok({"mode": context.session.mode})


async def reload_runtime_tool(context: ToolContext, arguments: dict):
    del arguments
    summary = await context.runtime.reload_extensions()
    return ok(summary)


async def add_custom_provider_tool(context: ToolContext, arguments: dict):
    name = str(arguments.get("name", "")).strip()
    provider_type = str(arguments.get("type", "openai_compatible")).strip()
    base_url = str(arguments.get("base_url", "")).strip() or None
    api_key = str(arguments.get("api_key", "")).strip()
    default_model = str(arguments.get("default_model", "")).strip() or None
    if not name:
        return fail("name is required")
    context.runtime.add_provider(name=name, provider_type=provider_type, api_key=api_key, base_url=base_url, default_model=default_model)
    save_config(context.config)
    return ok({"provider": name, "type": provider_type, "base_url": base_url, "default_model": default_model})


def build_tools() -> list[ToolSpec]:
    return [
        ToolSpec(
            name="runtime_info",
            description="Return current runtime/session/config information.",
            parameters={"type": "object", "properties": {}},
            handler=runtime_info_tool,
        ),
        ToolSpec(
            name="config_get",
            description="Read a config key by dotted path, or return the full config root.",
            parameters={
                "type": "object",
                "properties": {"key": {"type": "string"}},
            },
            handler=config_get_tool,
        ),
        ToolSpec(
            name="config_set",
            description="Update a config key by dotted path and save config.yaml.",
            parameters={
                "type": "object",
                "properties": {
                    "key": {"type": "string"},
                    "value": {},
                },
                "required": ["key", "value"],
            },
            handler=config_set_tool,
            dangerous=True,
        ),
        ToolSpec(
            name="set_provider",
            description="Switch the active provider for the current session.",
            parameters={
                "type": "object",
                "properties": {"provider_name": {"type": "string"}},
                "required": ["provider_name"],
            },
            handler=set_provider_tool,
        ),
        ToolSpec(
            name="set_model",
            description="Switch the active model for the current session.",
            parameters={
                "type": "object",
                "properties": {"model": {"type": "string"}},
                "required": ["model"],
            },
            handler=set_model_tool,
        ),
        ToolSpec(
            name="set_mode",
            description="Switch shell safety mode: safe, yolo, or god.",
            parameters={
                "type": "object",
                "properties": {"mode": {"type": "string"}},
                "required": ["mode"],
            },
            handler=set_mode_tool,
            dangerous=True,
        ),
        ToolSpec(
            name="reload_runtime",
            description="Reload skills and other runtime extensions without restarting.",
            parameters={"type": "object", "properties": {}},
            handler=reload_runtime_tool,
            dangerous=True,
        ),
        ToolSpec(
            name="add_custom_provider",
            description="Add or replace a custom provider in config and runtime.",
            parameters={
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "type": {"type": "string"},
                    "base_url": {"type": "string"},
                    "api_key": {"type": "string"},
                    "default_model": {"type": "string"},
                },
                "required": ["name", "type"],
            },
            handler=add_custom_provider_tool,
            dangerous=True,
        ),
    ]
