///|
/// auth_interaction.mbt — UI abstraction for OAuth user interaction.
///
/// OAuth flows need to communicate with the user: show a URL to open, display
/// a device code, report progress, or prompt for manual input. Hosts inject
/// an AuthInteraction impl that bridges to their UI (TUI, web, headless).

///|
/// Message types sent to the host during OAuth.
pub(all) enum AuthMessage {
  AuthUrl(String) // open this URL in a browser
  DeviceCode(String, String) // (verification_uri, user_code) — display both
  Progress(String) // human-readable status update
}

///|
pub(open) trait AuthInteraction {
  /// Notify the user of a step (show URL, display code, etc.). Never blocks.
  fn notify(Self, message : AuthMessage) -> Unit

  /// Check if the user wants to cancel. Called between poll iterations.
  /// Hosts return true to abort the flow.
  fn is_cancelled(Self) -> Bool
}

///|
/// A no-op AuthInteraction for headless/CI use. All notifications are
/// discarded and cancellation is never signalled.
pub(all) struct NoopAuthInteraction {}

///|
pub fn NoopAuthInteraction::NoopAuthInteraction() -> NoopAuthInteraction {
  NoopAuthInteraction::{ }
}

///|
pub impl AuthInteraction for NoopAuthInteraction with fn notify(
  _self : NoopAuthInteraction,
  _message : AuthMessage,
) {
  ()
}

///|
pub extend NoopAuthInteraction with AuthInteraction::{notify, is_cancelled}

///|
pub impl AuthInteraction for NoopAuthInteraction with fn is_cancelled(
  _self : NoopAuthInteraction,
) -> Bool {
  false
}

///|
/// Provider-neutral prompt options used by non-OAuth authentication flows.
/// The host renders these without knowing which provider requested them.
pub(all) struct AuthPromptOption {
  id : String
  label : String
  description : String?
}

///|
pub fn AuthPromptOption::AuthPromptOption(
  id~ : String,
  label~ : String,
  description? : String? = None,
) -> AuthPromptOption {
  { id, label, description, }
}

///|
/// A provider-neutral interactive authentication request. Secret values must
/// never be echoed by hosts or included in diagnostics.
pub(all) enum AuthPromptRequest {
  Secret(message~ : String)
  Select(message~ : String, options~ : Array[AuthPromptOption])
}

///|
/// Optional prompt seam for provider-owned API-key login. It is deliberately
/// separate from `AuthInteraction` so existing OAuth-only hosts remain source
/// compatible; a host that advertises API-key login implements both traits.
pub(open) trait AuthPromptInteraction {
  /// Prompt for a secret or select option. Cancellation and UI failures are
  /// typed OAuth errors so provider login cannot silently continue.
  async fn prompt(Self, request : AuthPromptRequest) -> String raise OAuthError
}

///|
/// Headless prompt implementation for tests. It fails loudly because an
/// unattended host must not pretend it obtained an API key.
pub(all) struct NoopAuthPromptInteraction {}

///|
pub fn NoopAuthPromptInteraction::NoopAuthPromptInteraction() -> NoopAuthPromptInteraction {
  NoopAuthPromptInteraction::{ }
}

///|
pub impl AuthPromptInteraction for NoopAuthPromptInteraction with fn prompt(
  _self : NoopAuthPromptInteraction,
  _request : AuthPromptRequest,
) -> String raise OAuthError {
  raise OAuthError::Cancelled
}

///|
pub extend NoopAuthPromptInteraction with AuthPromptInteraction::{prompt}