"""JHED detection from STS/SSO caller identity."""

from __future__ import annotations

from botocore.exceptions import BotoCoreError, ClientError

from alice_cli import personality
from alice_cli.aws.session import get_session
from alice_cli.aws.sts import STSClientWrapper
from alice_cli.console import print_status, spinner
from alice_cli.errors import AuthError
from alice_cli.logging import get_logger
from alice_cli.models import CLIConfig, UsernameResult

log = get_logger(__name__)


def detect_identity_from_key(access_key: str | None) -> str:
    """Extract a display name from the Bedrock access key alias.

    The ``BEDROCK_ACCESS_KEY`` (``service_credential_alias``) follows the
    pattern ``BedrockAPIKey-<JHED>-at-<ACCOUNT>``.  We extract the JHED
    portion when the pattern matches, otherwise return the raw value.

    Returns ``"unknown"`` when the access key is empty / absent.
    """
    if not access_key:
        log.debug("identity_detection_failed", reason="empty_access_key")
        return "unknown"

    # Pattern: BedrockAPIKey-<username>-at-<account_id>
    if access_key.startswith("BedrockAPIKey-") and "-at-" in access_key:
        username = access_key.removeprefix("BedrockAPIKey-").split("-at-", maxsplit=1)[0]
        log.debug("identity_detected_from_key", username=username, method="api_key")
        return username

    log.debug("identity_passthrough", access_key_prefix=access_key[:15])
    return access_key


def resolve_username(config: CLIConfig) -> str:
    """Resolve the current user's identity from config, printing status to stderr.

    Uses API key mode when an API key is configured without a profile;
    otherwise calls STS via the SSO profile.

    Args:
        config: Resolved CLI configuration.

    Returns:
        The resolved username / JHED.
    """
    if config.bedrock_secret_key and not config.profile:
        username = detect_identity_from_key(config.bedrock_access_key)
        print_status(personality.status_using_api_key(username), config.quiet)
        return username

    with spinner(personality.status_detecting_identity(), config.quiet):
        result = detect_username(config.profile, config.region)
    print_status(personality.status_identity_detected(result.username), config.quiet)
    return result.username


def detect_username(profile: str | None, region: str) -> UsernameResult:
    """Call STS get-caller-identity and extract the JHED from the ARN session name.

    Args:
        profile: AWS CLI profile name, or None if not provided.
        region: AWS region to use for the STS call.

    Returns:
        UsernameResult with username, session_name, and full ARN.

    Raises:
        AuthError: If no profile is provided, STS call fails, or JHED cannot be extracted.
    """
    if profile is None:
        log.warning("auth_failed", reason="no_profile")
        raise AuthError(personality.error_no_profile())

    log.debug("sts_call_starting", profile=profile, region=region)
    try:
        session = get_session(profile=profile, region=region)
        sts = STSClientWrapper.from_session(session)
        identity = sts.get_caller_identity()
    except (ClientError, BotoCoreError) as exc:
        from alice_cli.error_handler import extract_aws_error, handle_sts_error

        error = extract_aws_error(exc)
        log.error("sts_call_failed", profile=profile, region=region, **error.to_dict())
        raise handle_sts_error(exc, profile=profile) from exc

    arn: str = identity["Arn"]
    # ARN format: arn:aws:sts::ACCOUNT:assumed-role/ROLE/session_name
    arn_parts = arn.split(":")
    account_id = arn_parts[4] if len(arn_parts) > 4 else ""
    role_name = arn_parts[5].split("/")[1] if len(arn_parts) > 5 else ""
    is_federated = role_name.startswith("AWSReservedSSO_")

    session_name = arn.rsplit("/", maxsplit=1)[-1]

    if "@" not in session_name:
        log.warning("username_extraction_failed", session_name=session_name, arn=arn)
        raise AuthError(personality.error_username_extraction(session_name))

    username = session_name.split("@", maxsplit=1)[0]
    log.info("auth_success", username=username, profile=profile, region=region, method="sso")

    return UsernameResult(
        username=username,
        session_name=session_name,
        arn=arn,
        account_id=account_id,
        is_federated=is_federated,
    )
