"""Admin credentials grant command implementation."""

from datetime import datetime
from typing import Optional
from uuid import UUID

import typer

from cli.commands.admin.credentials.grant.presenter import present_grant_success
from cli.commands.flag_utils import require_one_of, require_exclusive, validate_uuid
from cli.infrastructure.command import async_command, authenticated_client
from alloy_runtime_types.dtos.credentials import GrantSystemCredentialRequest


def admin_credentials_grant_command(
    credential_id: str = typer.Option(
        ...,
        "--credential",
        help="System credential ID",
    ),
    user_id: Optional[str] = typer.Option(
        None,
        "--user",
        help="User ID (mutually exclusive with --org)",
    ),
    organization_id: Optional[str] = typer.Option(
        None,
        "--org",
        help="Organization ID (mutually exclusive with --user)",
    ),
    expires_at: Optional[str] = typer.Option(
        None,
        "--expires-at",
        help="Expiration (ISO 8601)",
    ),
) -> None:
    """Grant system credential access (requires system admin).

    Exactly one of --user or --org required.

    Examples:

        alloy admin credentials grant --credential <id> --org <org-id>
        alloy admin credentials grant --credential <id> --user <user-id>
    """
    _execute_grant(
        credential_id=credential_id,
        user_id=user_id,
        organization_id=organization_id,
        expires_at=expires_at,
    )


@async_command
async def _execute_grant(
    credential_id: str,
    user_id: Optional[str],
    organization_id: Optional[str],
    expires_at: Optional[str],
) -> None:
    """Execute the credential grant operation.

    Args:
        credential_id: System credential ID (string UUID)
        user_id: Optional user ID (string UUID)
        organization_id: Optional organization ID (string UUID)
        expires_at: Optional expiration datetime (ISO 8601 string)

    Raises:
        typer.BadParameter: If UUID or datetime format is invalid
        typer.BadParameter: If neither or both target IDs are provided
        ConfigurationError: If environment variables are missing
        AuthenticationError: If API key is invalid
        ForbiddenError: If user is not system admin
        ValidationError: If request data is invalid (neither/both targets)
        ConflictError: If grant already exists
        ServerError: If server returns 5xx error
    """
    # Validate and convert credential_id to UUID
    credential_uuid = validate_uuid(credential_id, "credential")

    # Validate mutual exclusivity at CLI level for better UX
    require_one_of(("--user", user_id), ("--org", organization_id))
    require_exclusive(("--user", user_id), ("--org", organization_id))

    # Convert UUIDs
    user_uuid: Optional[UUID] = None
    org_uuid: Optional[UUID] = None

    if user_id:
        user_uuid = validate_uuid(user_id, "user")

    if organization_id:
        org_uuid = validate_uuid(organization_id, "organization")

    # Parse expires_at if provided
    expires_datetime: Optional[datetime] = None
    if expires_at:
        try:
            expires_datetime = datetime.fromisoformat(expires_at.replace("Z", "+00:00"))
        except ValueError:
            raise typer.BadParameter(
                f"Invalid datetime format: '{expires_at}'. Must be ISO 8601 format (e.g., '2025-12-31T23:59:59Z')"
            )

    # Build request
    request = GrantSystemCredentialRequest(
        credential_id=credential_uuid,
        user_id=user_uuid,
        organization_id=org_uuid,
        expires_at=expires_datetime,
    )

    # Execute API call with authenticated client
    async with authenticated_client() as (_config, client):
        response = await client.grant_system_credential(request)

    # Present success output
    present_grant_success(response)
