#' Get default Azure tenant ID
#'
#' @description
#' Retrieves the Azure tenant ID in priority order:
#' 1. `AZURE_TENANT_ID` environment variable
#' 2. Built-in fallback (`"common"`)
#'
#' @return A character string with the tenant ID
#'
#' @export
#' @examples
#' default_azure_tenant_id()
default_azure_tenant_id <- function() {
  Sys.getenv(
    environment_variables$azure_tenant_id,
    unset = azure_client$tenant_id
  )
}


#' Get default Azure client ID
#'
#' @description
#' Retrieves the Azure client ID in priority order:
#' 1. `AZURE_CLIENT_ID` environment variable
#' 2. Built-in fallback (Microsoft's public Azure CLI client ID)
#'
#' @return A character string with the client ID
#'
#' @export
#' @examples
#' default_azure_client_id()
default_azure_client_id <- function() {
  Sys.getenv(
    environment_variables$azure_client_id,
    unset = azure_client$client_id
  )
}


default_azure_cli_client_id <- function() {
  azure_client$client_id
}


#' Get default Azure client secret
#'
#' @description
#' Retrieves the Azure client secret from the `AZURE_CLIENT_SECRET` environment
#' variable, or returns `NA_character_` if not set.
#'
#' @return A character string with the client secret, or `NA_character_` if not set
#'
#' @export
#' @examples
#' default_azure_client_secret()
default_azure_client_secret <- function() {
  res <- Sys.getenv(
    environment_variables$azure_client_secret,
    unset = NA_character_
  )

  if (is.na(res)) {
    NULL
  } else {
    res
  }
}


#' Get default Azure refresh token
#'
#' @description
#' Retrieves the Azure refresh token from the `AZURE_REFRESH_TOKEN` environment
#' variable, or returns `NULL` if not set.
#'
#' @return A character string with the refresh token, or `NULL` if not set
#'
#' @export
#' @examples
#' default_refresh_token()
default_refresh_token <- function() {
  res <- Sys.getenv(
    environment_variables$azure_refresh_token,
    unset = NA_character_
  )

  if (is.na(res)) {
    NULL
  } else {
    res
  }
}


#' Get default Azure OAuth scope
#'
#' @description
#' Returns the default OAuth scope for a specified Azure resource.
#'
#' @param resource A character string specifying the Azure resource. Must be one of:
#'   `"azure_arm"` (Azure Resource Manager), `"azure_graph"` (Microsoft Graph),
#'   `"azure_storage"` (Azure Storage), or `"azure_key_vault"` (Azure Key Vault).
#'   Defaults to `"azure_arm"`.
#'
#' @return A character string with the OAuth scope URL
#'
#' @export
#' @examples
#' default_azure_scope()
#' default_azure_scope("azure_graph")
default_azure_scope <- function(resource = "azure_arm") {
  resource <- rlang::arg_match(resource, values = names(azure_scopes))
  azure_scopes[[resource]]
}


#' Create default Azure OAuth client
#'
#' @description
#' Creates an [httr2::oauth_client()] configured for Azure authentication.
#'
#' @param client_id A character string specifying the client ID. Defaults to
#'   [default_azure_client_id()].
#' @param client_secret A character string specifying the client secret. Defaults
#'   to `NULL`.
#' @param name A character string specifying the client name. Defaults to `NULL`.
#'
#' @return An [httr2::oauth_client()] object
#'
#' @export
#' @examples
#' client <- default_azure_oauth_client()
#' client <- default_azure_oauth_client(
#'   client_id = "my-client-id",
#'   client_secret = "my-secret"
#' )
default_azure_oauth_client <- function(
  client_id = default_azure_client_id(),
  client_secret = NULL,
  name = NULL
) {
  httr2::oauth_client(
    name = name,
    id = client_id,
    token_url = default_azure_url("token"),
    secret = client_secret,
    auth = "body"
  )
}


#' Get default Azure OAuth URLs
#'
#' @description
#' Constructs Azure OAuth 2.0 endpoint URLs for a given tenant and authority host.
#'
#' @param endpoint A character string specifying which endpoint URL to return.
#'   Must be one of: `"authorize"`, `"token"`, or `"devicecode"`. If `NULL`
#'   (default), returns a list of all endpoint URLs.
#' @param oauth_host A character string specifying the Azure authority host.
#'   Defaults to [default_azure_host()].
#' @param tenant_id A character string specifying the tenant ID. Defaults to
#'   [default_azure_tenant_id()].
#'
#' @return If `endpoint` is specified, returns a character string with the URL.
#'   If `endpoint` is `NULL`, returns a named list of all endpoint URLs.
#'
#' @export
#' @examples
#' # Get all URLs
#' default_azure_url()
#'
#' # Get specific endpoint
#' default_azure_url("token")
#'
#' # Custom tenant
#' default_azure_url("authorize", tenant_id = "my-tenant-id")
default_azure_url <- function(
  endpoint = NULL,
  oauth_host = default_azure_host(),
  tenant_id = default_azure_tenant_id()
) {
  validate_tenant_id(tenant_id)

  if (!rlang::is_string(oauth_host) || !nzchar(oauth_host)) {
    cli::cli_abort(
      "{.arg oauth_host} must be a non-empty string, not {.obj_type_friendly {oauth_host}}"
    )
  }

  oauth_host <- sub("/+$", "", oauth_host)
  oauth_host <- sub("^https?://", "", oauth_host)
  oauth_base <- rlang::englue("https://{oauth_host}/{tenant_id}/oauth2/v2.0")

  urls <- c(
    authorize = paste0(oauth_base, "/authorize"),
    token = paste0(oauth_base, "/token"),
    devicecode = paste0(oauth_base, "/devicecode")
  )

  if (!is.null(endpoint)) {
    endpoint <- rlang::arg_match(endpoint, values = names(urls))
    return(urls[[endpoint]])
  }

  as.list(urls)
}


#' Get default Azure authority host
#'
#' @description
#' Retrieves the Azure authority host in priority order:
#' 1. `AZURE_AUTHORITY_HOST` environment variable
#' 2. Built-in fallback (`login.microsoftonline.com`)
#'
#' @return A character string with the authority host URL
#'
#' @export
#' @examples
#' default_azure_host()
default_azure_host <- function() {
  host <- Sys.getenv(
    environment_variables$azure_authority_host,
    unset = azure_authority_hosts$azure_public_cloud
  )

  if (!rlang::is_string(host) || !nzchar(host)) {
    cli::cli_abort(
      "{.arg host} must be a non-empty string, not {.obj_type_friendly {host}}"
    )
  }

  host <- sub("/+$", "", host)
  sub("^https?://", "", host)
}

#' Get default Azure Storage DFS endpoint suffix
#'
#' @description
#' Returns the default endpoint suffix used to construct Azure Data Lake Storage
#' Gen2 DFS URLs.
#'
#' @return A character string with the DFS endpoint suffix.
#'
#' @export
#' @examples
#' default_storage_endpoint()
default_storage_endpoint <- function() {
  azure_storage_endpoints$dfs
}

#' Get default Azure configuration directory
#'
#' @description
#' Retrieves the Azure configuration directory from the `AZURE_CONFIG_DIR`
#' environment variable, or falls back to the platform-specific default.
#'
#' @return A character string with the Azure configuration directory path
#'
#' @export
#' @examples
#' default_azure_config_dir()
default_azure_config_dir <- function() {
  Sys.getenv(
    "AZURE_CONFIG_DIR",
    unset = if (.Platform$OS.type == "windows") {
      normalizePath(
        file.path(Sys.getenv("USERPROFILE"), ".azure"),
        winslash = "/",
        mustWork = FALSE
      )
    } else {
      "~/.azure"
    }
  )
}

#' Get default MSAL token cache path
#'
#' @description
#' Returns the path to the MSAL token cache file shared by the Azure CLI and
#' Azure SDKs. Defaults to `msal_token_cache.json` inside the Azure config
#' directory (see [default_azure_config_dir()]).
#'
#' @return A character string with the path to the MSAL token cache file.
#'
#' @seealso [default_azure_config_dir()], [write_msal_token()]
#'
#' @export
default_msal_token_cache <- function() {
  file.path(default_azure_config_dir(), "msal_token_cache.json")
}


#' Get default OAuth redirect URI
#'
#' @description
#' Constructs a redirect URI for OAuth flows. If the provided URI doesn't have
#' a port, assigns a random port using [httpuv::randomPort()].
#'
#' @param redirect_uri A character string specifying the redirect URI. Defaults
#'   to [httr2::oauth_redirect_uri()].
#'
#' @return A character string with the redirect URI
#'
#' @export
#' @examples
#' default_redirect_uri()
default_redirect_uri <- function(redirect_uri = httr2::oauth_redirect_uri()) {
  parsed <- httr2::url_parse(redirect_uri)

  if (is.null(parsed$port)) {
    parsed$port <- random_port()
  }

  httr2::url_build(parsed)
}

#' Get default federated token file path
#'
#' @description
#' Retrieves the path to the federated identity token file from the
#' `AZURE_FEDERATED_TOKEN_FILE` environment variable, or returns `NULL` if
#' not set. Used by [WorkloadIdentityCredential].
#'
#' @return A character string with the file path, or `NULL` if not set
#'
#' @export
#' @examples
#' default_federated_token_file()
default_federated_token_file <- function() {
  res <- Sys.getenv(
    environment_variables$azure_federated_token_file,
    unset = NA_character_
  )

  if (is.na(res)) NULL else res
}
