from __future__ import annotations

import re
import uuid
from typing import Any

from fastmcp.exceptions import ToolError

from mcp_eregistrations_keycloak.keycloak_client import KeycloakAdminClient


def _extract_items(data: Any) -> list[Any]:
    """Extract items from a possibly truncated response."""
    if isinstance(data, dict) and data.get("truncated"):
        return list(data["items"])
    return list(data)


_REALM_RE = re.compile(r"^[a-zA-Z0-9_.\-]+$")
_ROLE_NAME_RE = re.compile(r"^[a-zA-Z0-9_.@ \-]+$")

_REALM_UPDATABLE_FIELDS = frozenset(
    {
        "displayName",
        "enabled",
        "registrationAllowed",
        "resetPasswordAllowed",
        "loginWithEmailAllowed",
        "duplicateEmailsAllowed",
        "verifyEmail",
        "bruteForceProtected",
        "permanentLockout",
        "maxFailureWaitSeconds",
        "minimumQuickLoginWaitSeconds",
        "waitIncrementSeconds",
        "quickLoginCheckMilliSeconds",
        "maxDeltaTimeSeconds",
        "failureFactor",
        "sslRequired",
        "defaultSignatureAlgorithm",
        "accessTokenLifespan",
        "ssoSessionIdleTimeout",
        "ssoSessionMaxLifespan",
    }
)

_USER_UPDATABLE_FIELDS = frozenset(
    {
        "email",
        "firstName",
        "lastName",
        "enabled",
        "emailVerified",
        "requiredActions",
        "attributes",
    }
)

_ROLE_UPDATABLE_FIELDS = frozenset(
    {
        "name",
        "description",
        "attributes",
        "composite",
    }
)


def _validate_realm(realm: str) -> None:
    if not _REALM_RE.match(realm):
        raise ToolError(
            f"Invalid realm name '{realm}'. "
            "Must contain only alphanumeric, hyphens, underscores, dots."
        )


def _validate_user_id(user_id: str) -> None:
    try:
        uuid.UUID(user_id)
    except ValueError:
        raise ToolError(
            f"Invalid user ID '{user_id}'. Must be a valid UUID "
            f"(e.g., '550e8400-e29b-41d4-a716-446655440000')."
        )


def _validate_role_name(role_name: str) -> None:
    if not _ROLE_NAME_RE.match(role_name):
        raise ToolError(
            f"Invalid role name '{role_name}'. "
            "Must contain only alphanumeric, dots, underscores, @, spaces, hyphens."
        )


def _resolve_realm(
    realm: str | None,
    instance: str | None,
    client: KeycloakAdminClient,
) -> str:
    """Resolve realm: explicit > instance config > error."""
    if realm:
        _validate_realm(realm)
        return realm
    resolved = client.default_realm
    if resolved:
        _validate_realm(resolved)
        return resolved
    raise ToolError(
        "No realm specified and none configured for this instance. "
        "Pass realm explicitly or configure keycloak_realm in instance config."
    )


def _filter_update_fields(
    updates: dict[str, Any], allowed: frozenset[str], resource: str
) -> dict[str, Any]:
    """Filter updates to allowed fields, raise on rejected fields."""
    rejected = set(updates.keys()) - allowed
    if rejected:
        raise ToolError(
            f"Cannot update {resource} fields: {', '.join(sorted(rejected))}. "
            f"Allowed fields: {', '.join(sorted(allowed))}."
        )
    return {k: v for k, v in updates.items() if k in allowed}
