from typing import Any

from mcp.types import ToolAnnotations

from mcp_eregistrations_keycloak.audit.logger import KcAuditLogger
from mcp_eregistrations_keycloak.audit.models import KcObjectType
from mcp_eregistrations_keycloak.keycloak_client import (
    KeycloakAdminClient,
    KeycloakClientError,
    translate_error,
)
from mcp_eregistrations_keycloak.server import mcp
from mcp_eregistrations_keycloak.tools.validation import _resolve_realm

_THEME_FIELDS = ("loginTheme", "accountTheme", "adminTheme", "emailTheme")


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
async def kc_list_themes(
    instance: str | None = None,
) -> dict[str, Any]:
    """List available themes from server info.

    Args:
        instance: Instance name, or None for auto-select.

    Returns:
        dict with themes by type.
    """
    try:
        async with KeycloakAdminClient.for_instance(instance) as client:
            info = await client.get("/serverinfo")
            themes = info.get("themes", {})
            return {
                "themes": {
                    theme_type: [t.get("name") for t in theme_list]
                    for theme_type, theme_list in themes.items()
                },
            }
    except KeycloakClientError as e:
        raise translate_error(e, resource_type="server themes") from e


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
async def kc_get_realm_theme(
    realm: str | None = None,
    instance: str | None = None,
) -> dict[str, Any]:
    """Get current theme settings for a realm.

    Args:
        realm: Realm name, or None for instance default.
        instance: Instance name, or None for auto-select.

    Returns:
        dict with loginTheme, accountTheme, adminTheme, emailTheme.
    """
    try:
        async with KeycloakAdminClient.for_instance(instance) as client:
            r = _resolve_realm(realm, instance, client)
            realm_config = await client.get(f"/realms/{r}")
            return {
                "realm": r,
                **{field: realm_config.get(field) for field in _THEME_FIELDS},
            }
    except KeycloakClientError as e:
        raise translate_error(e, resource_type="realm theme", resource_id=realm) from e


@mcp.tool()
async def kc_set_realm_theme(
    themes: dict[str, str],
    realm: str | None = None,
    instance: str | None = None,
) -> dict[str, Any]:
    """Set theme(s) for a realm. Audited write operation.

    Args:
        themes: Theme settings (loginTheme, accountTheme, adminTheme, emailTheme).
        realm: Realm name, or None for instance default.
        instance: Instance name, or None for auto-select.

    Returns:
        dict with realm, updated_themes, previous_themes.
    """
    valid_keys = set(_THEME_FIELDS)
    invalid = set(themes.keys()) - valid_keys
    if invalid:
        from fastmcp.exceptions import ToolError

        raise ToolError(
            f"Invalid theme keys: {', '.join(sorted(invalid))}. "
            f"Valid keys: {', '.join(sorted(valid_keys))}."
        )
    logger = KcAuditLogger.for_instance(instance)
    audit_id: str | None = None
    try:
        async with KeycloakAdminClient.for_instance(instance) as client:
            r = _resolve_realm(realm, instance, client)
            audit_id = await logger.record_pending(
                None,
                "update",
                KcObjectType.THEME,
                {"realm": r, "themes": list(themes.keys())},
            )
            realm_config = await client.get(f"/realms/{r}")
            previous = {field: realm_config.get(field) for field in themes}
            await logger.save_rollback_state(
                audit_id,
                KcObjectType.THEME,
                r,
                {field: realm_config.get(field) for field in _THEME_FIELDS},
            )
            await client.put(f"/realms/{r}", data=themes)
            outcome = {
                "realm": r,
                "updated_themes": themes,
                "previous_themes": previous,
                "status": "updated",
            }
            await logger.mark_success(audit_id, outcome)
            return outcome
    except KeycloakClientError as e:
        if audit_id is not None:
            await logger.mark_failed(audit_id, str(e))
        raise translate_error(e, resource_type="realm theme", resource_id=realm) from e
