///|
/// Controls what Proton does after the last application window closes.
pub(all) enum LastWindowClosedPolicy {
  Quit
  KeepRunning
} derive(Eq, Debug)

///|
pub extend LastWindowClosedPolicy with Eq::{not_equal, equal}

///|
pub extend LastWindowClosedPolicy with Debug::{to_repr}

///|
/// How an application answers a cancelable quit event.
///
/// `Prevent` is the typed counterpart of Electron's `event.preventDefault()`
/// on `before-quit` and `will-quit`.
pub(all) enum ApplicationQuitDecision {
  Allow
  Prevent
} derive(Eq, Debug)

///|
pub extend ApplicationQuitDecision with Eq::{not_equal, equal}

///|
pub extend ApplicationQuitDecision with Debug::{to_repr}

///|
/// Selects browser storage that can be cleared from a live Proton session.
pub(all) enum StorageDataKind {
  Cookies
  HttpCache
  AllSupported
} derive(Eq, Debug)

///|
pub extend StorageDataKind with Eq::{not_equal, equal}

///|
pub extend StorageDataKind with Debug::{to_repr}

///|
/// An Electron-style native image with one or more scale representations.
pub struct NativeImage {
  image : @native.NativeImage
}

///|
/// A failure while creating, reading, or converting a native image.
pub(all) suberror NativeImageError {
  OperationFailed(action~ : String, status~ : Int32, detail~ : String)
} derive(Debug, Eq)

///|
pub extend NativeImageError with Eq::{not_equal, equal}

///|
pub extend NativeImageError with Debug::{to_repr}

///|
pub fn NativeImageError::message(self : NativeImageError) -> String {
  match self {
    OperationFailed(action~, status~, detail~) =>
      action + " failed (" + status.to_string() + "): " + detail
  }
}

///|
impl Show for NativeImageError with fn output(self, logger) {
  logger.write_string(self.message())
}

///|
pub extend NativeImageError with Show::{to_string, output}

///|
/// High-level application facade for ordinary Proton apps.
struct App {
  mut main_window_config : WindowConfig
  windows : Array[(String, WindowConfig, Bool)]
  mut debug_level_value : Int32
  mut headless_value : Bool
  mut accessibility_mode_value : AccessibilityMode
  mut application_identity : ApplicationIdentitySource?
  mut single_instance_enabled : Bool
  mut session_partition_value : String?
  mut proxy_server_value : String?
  mut proxy_bypass_value : String?
  mut explicit_locale : @locale.Locale?
  path_overrides : Map[String, String]
  mut electron_default_logs_path : Bool
  mut create_logs_path : Bool
  mut bridge_startup_timeout_value_ms : Int32
  mut last_window_closed_policy_value : LastWindowClosedPolicy
  mut menu : MenuBar?
  url_schemes : Array[String]
  web_request_cancel_prefixes : Array[String]
  web_request_redirect_prefixes : Array[(String, String)]
  web_request_header_prefixes : Array[(String, String, String)]
  document_extensions : Array[String]
  mut update_channel : ResolvedUpdateChannel?
  command_capabilities : Array[AppCommandCapability]
  extension_capabilities : Array[ExtensionCapabilityBinding]
  application_setup : Array[async (ApplicationContext) -> Unit]
  mut before_quit_handler : (async (ApplicationContext) -> ApplicationQuitDecision noraise)?
  mut will_quit_handler : (async (ApplicationContext) -> ApplicationQuitDecision noraise)?
  quit_handlers : Array[(ApplicationContext, Int32) -> Unit noraise]
  launch_input_handlers : Array[
    async (ApplicationContext, RuntimeLaunchInput) -> Unit noraise,
  ]
  window_event_handlers : Array[
    async (WindowHandle, WindowEvent) -> Unit noraise,
  ]
  window_created_handlers : Array[(WindowHandle) -> Unit noraise]
  web_contents_created_handlers : Array[(WebContentsHandle) -> Unit noraise]
  render_process_gone_handlers : Array[
    async (WebContentsHandle, RenderProcessGoneDetails) -> Unit noraise,
  ]
  session_created_handlers : Array[(ApplicationSession) -> Unit noraise]
  contents_event_handlers : Array[
    async (WebContentsHandle, WebContentsEvent) -> Unit noraise,
  ]
  mut download_handler : (async (WebContentsHandle, DownloadRequest) -> DownloadDecision noraise)?
  mut certificate_handler : (async (WebContentsHandle, CertificateError) -> BrowserPermissionDecision noraise)?
  mut media_handler : (async (WebContentsHandle, MediaPermissionRequest) -> BrowserPermissionDecision noraise)?
  download_event_handlers : Array[
    async (WebContentsHandle, DownloadEvent) -> Unit noraise,
  ]
  update_handlers : Array[async (PendingUpdate) -> Unit noraise]
  system_appearance_handlers : Array[async (SystemAppearance) -> Unit noraise]
  thumbar_button_handlers : Array[async (WindowHandle, String) -> Unit noraise]
  window_setup : Array[async (WindowContext) -> Unit]
  validation_errors : Array[AppConfigurationError]
}

///|
priv enum ApplicationIdentitySource {
  Configured(@proton_config.AppConfig)
  Explicit(String)
}

///|
/// Identifies one renderer page that may use a capability.
pub struct RendererTarget {
  window : String
  bundled : Bool
}

///|
priv struct AppCommandCapability {
  register : (@proton_command.CommandRegistrar) -> Unit raise
  targets : Array[RendererTarget]
}

///|
priv struct ExtensionCapabilityBinding {
  definition_id : UInt64
  spec : @proton_command.AppCommandExtensionSpec
  event_source : @proton_extension.EventSource?
  scope : Json
  targets : Array[RendererTarget]
}

///|
priv struct RegisteredAppCommandCapability {
  ops : Array[String]
  targets : Array[RendererTarget]
}

///|
priv struct CommandExtensionCatalog {
  specs : Map[String, @proton_command.AppCommandExtensionSpec]
  event_sources : Map[String, @proton_extension.EventSource]
}

///|
priv struct ResolvedExtensionCapability {
  spec : @proton_command.AppCommandExtensionDescriptor
  scope : Json
  targets : Array[RendererTarget]
}

///|
priv struct CommandHostBuild {
  extensions : Map[String, @proton_command.AppCommandExtensionDescriptor]
  runtime : CommandHostRuntime?
  app_capabilities : Array[RegisteredAppCommandCapability]
}

///|
let default_bridge_startup_timeout_ms = 30000

///|
let titlebar_area_op = "proton:window/get-titlebar-area"

///|
let titlebar_area_bridge_source =
  #|Object.defineProperty(globalThis.__MoonBit__, "getTitlebarArea", {
  #|  configurable: true,
  #|  enumerable: true,
  #|  value() {
  #|    return globalThis.__MoonBit__.core.invokeOp(
  #|      "proton:window/get-titlebar-area",
  #|      null,
  #|    );
  #|  },
  #|});
  #|

///|
/// Application startup settings and handlers shared by startup and the session.
/// Runtime handles and mutable lifecycle state belong to RuntimeSession.
priv struct ResolvedAppConfig {
  manifest : @manifest.AppManifest
  application_name : String
  permission_base_path : String
  application_identifier : String
  instance_identifier : String?
  url_schemes : Array[String]
  session_partition : String?
  web_request_cancel_prefixes : Array[String]
  web_request_redirect_prefixes : Array[(String, String)]
  web_request_header_prefixes : Array[(String, String, String)]
  document_extensions : Array[String]
  /// The update channel and the identity it updates, when configured by code.
  update_channel : ResolvedUpdateChannel?
  command_capabilities : Array[AppCommandCapability]
  extension_capabilities : Array[ExtensionCapabilityBinding]
  application_setup : Array[async (ApplicationContext) -> Unit]
  window_setup : Array[async (WindowContext) -> Unit]
  menu : @native.MenuBar?
  bridge_startup_timeout_ms : Int32
  headless : Bool
  accessibility_mode : AccessibilityMode
  proxy_server : String?
  proxy_bypass : String?
  window_configs : Map[String, WindowConfig]
  last_window_closed_policy : LastWindowClosedPolicy
  launch_input_handlers : Array[
    async (ApplicationContext, RuntimeLaunchInput) -> Unit noraise,
  ]
  system_appearance_handlers : Array[async (SystemAppearance) -> Unit noraise]
  thumbar_button_handlers : Array[async (WindowHandle, String) -> Unit noraise]
  window_event_handlers : Array[
    async (WindowHandle, WindowEvent) -> Unit noraise,
  ]
  window_created_handlers : Array[(WindowHandle) -> Unit noraise]
  web_contents_created_handlers : Array[(WebContentsHandle) -> Unit noraise]
  render_process_gone_handlers : Array[
    async (WebContentsHandle, RenderProcessGoneDetails) -> Unit noraise,
  ]
  session_created_handlers : Array[(ApplicationSession) -> Unit noraise]
  contents_event_handlers : Array[
    async (WebContentsHandle, WebContentsEvent) -> Unit noraise,
  ]
  before_quit_handler : (async (ApplicationContext) -> ApplicationQuitDecision noraise)?
  will_quit_handler : (async (ApplicationContext) -> ApplicationQuitDecision noraise)?
  quit_handlers : Array[(ApplicationContext, Int32) -> Unit noraise]
  download_handler : (async (WebContentsHandle, DownloadRequest) -> DownloadDecision noraise)?
  certificate_handler : (async (WebContentsHandle, CertificateError) -> BrowserPermissionDecision noraise)?
  media_handler : (async (WebContentsHandle, MediaPermissionRequest) -> BrowserPermissionDecision noraise)?
  download_event_handlers : Array[
    async (WebContentsHandle, DownloadEvent) -> Unit noraise,
  ]
  update_handlers : Array[async (PendingUpdate) -> Unit noraise]
  explicit_locale : @locale.Locale?
}

///|
/// Host-derived launch information, resolved after logging is initialized.
/// Contains no native handles or mutable runtime state.
priv struct RuntimeEnvironment {
  locale_preferences : @locale.LocalePreferences
  application_session : ApplicationSession
  application_executable : String
  application_arguments : Array[String]
}

///|
priv struct ResolvedUpdateChannel {
  endpoint : String
  public_keys : Array[String]
  check_on_launch : Bool
  freshness_days : Int32
}

///|
/// Optional command override for `ApplicationContext::relaunch`.
///
/// With neither field set, Proton repeats the current executable and command
/// line. Setting either field switches to Electron's override behavior: the
/// executable still defaults to the current executable, while omitted
/// arguments become an empty array.
pub(all) struct RelaunchOptions {
  executable : String?
  arguments : Array[String]?
} derive(Debug, Eq)

///|
pub extend RelaunchOptions with Eq::{not_equal, equal}

///|
pub extend RelaunchOptions with Debug::{to_repr}

///|
pub fn RelaunchOptions::RelaunchOptions(
  executable? : String,
  arguments? : Array[String],
) -> RelaunchOptions {
  RelaunchOptions::{ executable, arguments, }
}

///|
priv struct BridgeDispatchTask {
  request_id : Int64
  window : Int64
  task : @async.Task[@native.BridgeResponse?]
  mut state : BridgeRequestLifecycleState
}

///|
priv struct RunningWindow {
  id : String
  /// Identity of the native window slot. Native events carry this value, and
  /// it stays valid after the window handle itself is destroyed.
  native_id : Int64
  window : @native.Window
  config : WindowConfig
  permissions : WindowPermissionPolicy
  lifetime : WindowLifetime
  views : Array[RunningView]
  mut document : ResourceDocument?
  asset_root : String?
  mut bridge_ready : Bool
  mut state : SessionWindowState
  mut observed_state : WindowState?
  mut observed_browser_loading : Bool?
}

///|
priv struct RunningView {
  // Event identity survives native wrapper destruction.
  native_id : Int64
  id : String
  view : @native.View
  web_contents_policy : WebContentsPolicy
  mut document : ResourceDocument?
  mut observed_loading : Bool?
}

///|
priv struct ResourceDocument {
  url : String
  content : Bytes
}

///|
priv enum PreparedEntry {
  RemoteEntry(String)
  DocumentEntry(ResourceDocument, String?)
}

///|
priv struct ResourceResponse {
  status : Int32
  mime_type : String
  body : Bytes
}

///|
priv struct PendingResourceRequest {
  view : Int64?
  request_id : Int64
  window : Int64
  task : @async.Task[ResourceResponse]
}

///|
priv enum CloseCoordinatorState {
  CloseRunning = 0
  CloseBeforeQuit = 1
  CloseQuitRequested = 2
  CloseCollecting = 3
  CloseClosingWindows = 4
  CloseWillQuit = 5
  CloseCommitted = 7
} derive(Eq)

///|
priv struct PendingCloseDecision {
  window : Int64
  task : @async.Task[WindowCloseDecision]
  mut decision : WindowCloseDecision?
  mut native_request : Int64?
}

///|
priv struct ApplicationExit {
  exit_code : Int32
  forced : Bool
  update : @updater.PreparedUpdate?
}

///|
priv enum ExitPurpose {
  Quit(Int32)
  ForceExit(Int32)
  InstallUpdate
} derive(Eq)

///|
priv struct CloseCoordinator {
  mut state : CloseCoordinatorState
  pending : Array[PendingCloseDecision]
  mut pending_quit : @async.Task[ApplicationQuitDecision]?
  mut purpose : ExitPurpose
  mut relaunch_scheduled : Bool
  /// Whether the last-window policy already consumed the current windowless
  /// period, so a prevented quit is not retried until a window opens again.
  mut last_window_quit_handled : Bool
}

///|
priv enum SessionWindowState {
  WindowStarting = 0
  WindowOpen = 1
  WindowCloseRequested = 2
  WindowClosed = 3
}

///|
priv struct WindowLifetime {
  mut task : @async.Task[Unit]?
  mut ready : Bool
  mut closed : Bool
  mut startup_error : AppRunError?
  ready_signal : @async.CondVar
  close_signal : @async.CondVar
}

///|
priv struct PlannedWindow {
  id : String
  window : @manifest.WindowManifest
  entry : @manifest.AppEntry
  open_on_start : Bool
}

///|
priv struct PreparedWindow {
  plan : PlannedWindow
  entry : PreparedEntry
  bridge : @native.BridgeConfig?
  permissions : WindowPermissionPolicy
  browser_policy : @native.BrowserPolicy
  config : WindowConfig
}

///|
priv struct CommandHostRuntime {
  host : @core.AppCommandHost
  destroy_hooks : Array[CommandExtensionDestroyHook]
  start_hooks : Array[(@async.TaskGroup[Unit]) -> Unit raise AppRunError]
  event_sources : Array[CommandExtensionEventSource]
  mut closed : Bool
}

///|
priv struct CommandExtensionEventSource {
  extension_id : String
  extension_namespace : String
  source : @proton_extension.EventSource
  mut started : Bool
}

///|
priv struct CommandExtensionDestroyHook {
  extension_id : String
  callback : () -> Unit raise
}

///|
priv struct BridgePagePolicy {
  entry_origin : String?
}

///|
priv struct BridgeFrontendConfig {
  extensions : Array[@native.BridgeExtensionConfig]
  initialization_units : Array[@native.BridgeInitializationUnit]
}

///|
priv struct ResolvedPermissionGrant {
  source_origin : String
  extension_id : String
  ops : Array[String]
  scope : Json
}

///|
priv struct WindowPermissionPolicy {
  grants : Array[ResolvedPermissionGrant]
}

///|
/// Owns the mutable state of one running Proton application.
///
/// Native window ownership stays in this session. Public window references
/// are non-owning capabilities that route operations back through the session
/// instead of duplicating native lifecycle state.
priv struct RuntimeSession {
  destroy_window : (@native.Window) -> Unit raise @native.NativeError
  config : ResolvedAppConfig
  environment : RuntimeEnvironment
  updates : ApplicationUpdates
  runtime : @native.Runtime
  event_pump : RuntimeEventPump
  definitions : Array[PreparedWindow]
  windows : Array[RunningWindow]
  mut has_created_window : Bool
  command_host : CommandHostRuntime?
  pending_bridge : Array[BridgeDispatchTask]
  wakeup : RuntimeWakeup
  forward_menu_events : Bool
  monitor_bridge : Bool
  application_tasks : @async.TaskGroup[Unit]
  /// The single-instance lock this process holds, when the application
  /// declared `single_instance`. Released on demand and destroyed on exit.
  mut app_instance : @native.AppInstance?
  window_tasks : @async.TaskGroup[Unit]
  lifecycle_failures : Array[AppCleanupError]
  window_commands : Array[WindowSessionCommand]
  pending_window_opens : Array[PendingWindowOpen]
  pending_browser_requests : Array[PendingBrowserRequest]
  pending_resource_requests : Array[PendingResourceRequest]
  close_coordinator : CloseCoordinator
}

///|
priv enum DialogCompletionState {
  Waiting
  Completed(Result[String, @native.NativeError])
}

///|
priv struct PendingDialogCompletion {
  dialog : Int64
  mut state : DialogCompletionState
  changed : @async.CondVar
}

///|
priv struct DialogCompletionStore {
  pending : Array[PendingDialogCompletion]
}

///|
/// Sole owner of the native runtime event queue.
///
/// Dialog, cookie, and PDF completions are delivered directly to their waiters.
/// Other events remain queued until the runtime session dispatches them.
priv struct RuntimeEventPump {
  runtime : @native.Runtime
  dialog_completions : DialogCompletionStore
  cookie_completions : CookieCompletionStore
  pdf_completions : PdfCompletionStore
  session_events : Array[@native.RuntimeEvent]
}

///|
// Result delivery and closure can run before the waiter resumes. Keep the
// first result; routing and cancellation belong to each operation's owner.
priv struct Completion[T] {
  mut result : T?
  changed : @async.CondVar
}

///|
priv struct PendingCookieCompletion {
  request_id : Int64
  completion : Completion[
    Result[Array[@native.NativeCookieRecord], @native.NativeError],
  ]
}

///|
priv struct CookieCompletionStore {
  pending : Array[PendingCookieCompletion]
}

///|
priv enum WindowSessionCommand {
  Open(String, WindowOpenCompletion[WindowHandle])
}

///|
priv struct WindowOpenCompletion[T] {
  mut state : WindowOpenCompletionState[T]
  changed : @async.CondVar
}

///|
priv enum WindowOpenCompletionState[T] {
  WindowOpenPending
  WindowOpenSucceeded(T)
  WindowOpenFailed(WindowSessionError)
}

///|
priv struct PendingWindowOpen {
  id : String
  running : RunningWindow
  completion : WindowOpenCompletion[WindowHandle]
  mut activation : @async.Task[Unit]?
  timeout : @async.Task[Unit]
}

///|
priv struct PendingBrowserRequest {
  view : Int64?
  window : Int64
  request_id : Int64
  task : @async.Task[BrowserResponse]
}

///|
priv struct BrowserResponse {
  action : String
  path : String?
}

///|
/// A page hosted by a window or child view, bound to one native instance.
/// Obtaining this handle does not wait for native browser initialization, page
/// loading, or command bridge readiness. Operations requiring an initialized
/// browser can raise `WindowSessionError` during startup; do not assume that
/// all operations are queued until initialization completes.
pub struct WebContentsHandle {
  priv session : RuntimeSession
  id : String
  native_id : Int64
  priv target : WebContentsTarget
}

///|
priv enum WebContentsTarget {
  PrimaryPage
  ChildView(String, Int64)
}

///|
type ResolvedWebContents = @native.Contents

///|
/// The shared browser session of one application run.
/// Closing a window or view does not invalidate this handle. Operations fail
/// with `SessionError` once application runtime teardown begins.
pub struct SessionHandle {
  read_cookies : async (String?, Bool) -> Array[Cookie]
  write_cookie : (
    String,
    String,
    String,
    String?,
    String?,
    Bool,
    Bool,
    CookieSameSite,
  ) -> Unit raise SessionError
  remove_cookies : (String?, String?) -> Unit raise SessionError
  flush_cookie_store : () -> Unit raise SessionError
  clear_http_cache : () -> Unit raise SessionError
  clear_http_auth_cache : () -> Unit raise SessionError
  clear_certificate_exceptions : () -> Unit raise SessionError
  close_all_connections : () -> Unit raise SessionError
  clear_storage_data : (StorageDataKind) -> Unit raise SessionError
}

///|
/// A non-owning reference to one concrete web contents view instance.
///
/// Views follow the Electron `WebContentsView` model: each view is an
/// independent web page hosted inside its owning window's content area with
/// explicit top-left bounds, visibility, and z-order. The instance id
/// prevents a stale handle from targeting a later view that reuses the same
/// declarative id.
pub struct ViewHandle {
  priv session : RuntimeSession
  id : String
  native_id : Int64
  window_id : String
  priv window_native_id : Int64
}

///|
/// A non-owning reference to one concrete window instance.
///
/// The instance id prevents a stale handle from targeting a later window that
/// reuses the same declarative id.
pub struct WindowHandle {
  priv session : RuntimeSession
  id : String
  native_id : Int64
}

///|
/// Opens and locates windows declared by the application manifest.
pub struct WindowManager {
  open_window : async (String) -> WindowHandle
  find_window : (String) -> WindowHandle?
}

///|
/// An observed change to a running native window.
pub(all) enum WindowEvent {
  StateChanged(WindowState)
  Closed
  ReadyToShow
  Moved
  Resized
  Show
  Hide
  Focus
  Blur
  Minimize
  Restore
  Maximize
  Unmaximize
  EnterFullScreen
  LeaveFullScreen
} derive(Debug, Eq)

///|
pub extend WindowEvent with Eq::{not_equal, equal}

///|
pub extend WindowEvent with Debug::{to_repr}

///|
/// Derives Electron-style window transition events from two state snapshots.
/// The full `StateChanged` snapshot is always emitted after transition events.
fn window_state_events(
  previous : WindowState?,
  current : WindowState,
) -> Array[WindowEvent] {
  let events : Array[WindowEvent] = []
  match previous {
    None => if current.visible { events.push(ReadyToShow) }
    Some(previous) => {
      if previous.x != current.x || previous.y != current.y {
        events.push(Moved)
      }
      if previous.width != current.width || previous.height != current.height {
        events.push(Resized)
      }
      if !previous.visible && current.visible {
        events.push(Show)
      } else if previous.visible && !current.visible {
        events.push(Hide)
      }
      if !previous.focused && current.focused {
        events.push(Focus)
      } else if previous.focused && !current.focused {
        events.push(Blur)
      }
      if !previous.minimized && current.minimized {
        events.push(Minimize)
      } else if previous.minimized && !current.minimized {
        events.push(Restore)
      }
      if !previous.maximized && current.maximized {
        events.push(Maximize)
      } else if previous.maximized && !current.maximized {
        events.push(Unmaximize)
      }
      if !previous.fullscreen && current.fullscreen {
        events.push(EnterFullScreen)
      } else if previous.fullscreen && !current.fullscreen {
        events.push(LeaveFullScreen)
      }
    }
  }
  events.push(StateChanged(current))
  events
}

///|
/// Margins used when printing browser contents to PDF.
pub(all) enum PdfPrintMargins {
  Default
  NoMargins
  Custom(top~ : Double, right~ : Double, bottom~ : Double, left~ : Double)
} derive(Debug, Eq)

///|
pub extend PdfPrintMargins with Eq::{not_equal, equal}

///|
pub extend PdfPrintMargins with Debug::{to_repr}

///|
/// Electron-style PDF print settings. Paper dimensions and custom margins use
/// inches, and scale must be between `0.1` and `2.0`. An empty page range
/// prints the complete document.
pub(all) struct PdfPrintOptions {
  landscape : Bool
  print_background : Bool
  scale : Double
  paper_width : Double
  paper_height : Double
  prefer_css_page_size : Bool
  margins : PdfPrintMargins
  page_ranges : String
  display_header_footer : Bool
  header_template : String
  footer_template : String
  generate_tagged_pdf : Bool
  generate_document_outline : Bool
} derive(Debug, Eq)

///|
pub fn PdfPrintOptions::PdfPrintOptions(
  landscape~ : Bool = false,
  print_background~ : Bool = false,
  scale~ : Double = 1.0,
  paper_width~ : Double = 8.5,
  paper_height~ : Double = 11.0,
  prefer_css_page_size~ : Bool = false,
  margins~ : PdfPrintMargins = PdfPrintMargins::Default,
  page_ranges~ : String = "",
  display_header_footer~ : Bool = false,
  header_template~ : String = "",
  footer_template~ : String = "",
  generate_tagged_pdf~ : Bool = false,
  generate_document_outline~ : Bool = false,
) -> PdfPrintOptions {
  {
    landscape,
    print_background,
    scale,
    paper_width,
    paper_height,
    prefer_css_page_size,
    margins,
    page_ranges,
    display_header_footer,
    header_template,
    footer_template,
    generate_tagged_pdf,
    generate_document_outline,
  }
}

///|
pub extend PdfPrintOptions with Eq::{not_equal, equal}

///|
pub extend PdfPrintOptions with Debug::{to_repr}

///|
/// The result of an asynchronous native close request.
pub(all) enum WindowCloseDecision {
  Allow
  Deny
} derive(Debug, Eq)

///|
pub extend WindowCloseDecision with Eq::{not_equal, equal}

///|
pub extend WindowCloseDecision with Debug::{to_repr}

///|
pub(all) struct NavigationRequest {
  url : String
  http_method : String
  user_gesture : Bool
  redirect : Bool
} derive(Debug, Eq)

///|
pub extend NavigationRequest with Eq::{not_equal, equal}

///|
pub extend NavigationRequest with Debug::{to_repr}

///|
pub(all) enum NavigationDecision {
  Allow
  Deny
} derive(Debug, Eq)

///|
pub extend NavigationDecision with Eq::{not_equal, equal}

///|
pub extend NavigationDecision with Debug::{to_repr}

///|
pub(all) struct NewWindowRequest {
  url : String
  user_gesture : Bool
} derive(Debug, Eq)

///|
pub extend NewWindowRequest with Eq::{not_equal, equal}

///|
pub extend NewWindowRequest with Debug::{to_repr}

///|
pub(all) enum NewWindowDecision {
  Deny
  OpenInCurrent
  OpenInWindow(String)
} derive(Debug, Eq)

///|
pub extend NewWindowDecision with Eq::{not_equal, equal}

///|
pub extend NewWindowDecision with Debug::{to_repr}

///|
pub(all) struct DownloadRequest {
  id : Int32
  url : String
  suggested_name : String
} derive(Debug, Eq)

///|
pub extend DownloadRequest with Eq::{not_equal, equal}

///|
pub extend DownloadRequest with Debug::{to_repr}

///|
pub(all) enum DownloadDecision {
  Deny
  ShowSaveDialog
  SaveTo(String)
} derive(Debug, Eq)

///|
pub extend DownloadDecision with Eq::{not_equal, equal}

///|
pub extend DownloadDecision with Debug::{to_repr}

///|
pub(all) struct CertificateError {
  url : String
  error_code : Int32
} derive(Debug, Eq)

///|
pub extend CertificateError with Eq::{not_equal, equal}

///|
pub extend CertificateError with Debug::{to_repr}

///|
pub(all) struct MediaPermissionRequest {
  origin : String
  permissions : Int32
} derive(Debug, Eq)

///|
pub extend MediaPermissionRequest with Eq::{not_equal, equal}

///|
pub extend MediaPermissionRequest with Debug::{to_repr}

///|
pub(all) enum BrowserPermissionDecision {
  Allow
  Deny
} derive(Debug, Eq)

///|
pub extend BrowserPermissionDecision with Eq::{not_equal, equal}

///|
pub extend BrowserPermissionDecision with Debug::{to_repr}

///|
pub(all) struct DownloadEvent {
  id : Int32
  state : String
  received_bytes : Int64
  total_bytes : Int64
  percent : Int32
} derive(Debug, Eq)

///|
pub extend DownloadEvent with Eq::{not_equal, equal}

///|
pub extend DownloadEvent with Debug::{to_repr}

///|
/// Failures from runtime window lookup, creation, or control.
pub(all) suberror WindowSessionError {
  UnknownWindow(id~ : String)
  AlreadyOpen(id~ : String)
  ApplicationQuitting
  StaleWindow(id~ : String)
  UnknownView(id~ : String)
  AlreadyExists(id~ : String)
  StaleView(id~ : String)
  Cancelled
  OperationFailed(action~ : String, status~ : Int32, detail~ : String)
  StartupFailed(id~ : String, error~ : AppRunError)
} derive(Debug)

///|
pub extend WindowSessionError with Debug::{to_repr}

///|
priv enum AppLifecycleState {
  Constructing = 0
  Starting = 1
  Running = 2
  Closing = 3
  Draining = 4
  Destroying = 5
  Closed = 6
}

///|
/// An observed page event from a window or child view.
pub(all) enum WebContentsEvent {
  Closed
  /// The running page lost its command bridge. Reload or close this browser to recover.
  BridgeFailed(diagnostic~ : BridgeDiagnostic)
  LoadingChanged(is_loading~ : Bool)
  DidStartLoading
  DidFinishLoad
  Navigated(url~ : String)
  TitleUpdated(title~ : String)
  LoadFailed(url~ : String, error_code~ : Int32, error_text~ : String)
  FoundInPage(result~ : FindInPageResult)
  ResourceResponse(url~ : String, status_code~ : Int32)
  ResourceCompleted(url~ : String, status~ : Int32, received_bytes~ : Int64)
  /// A network resource request observed before Chromium sends it.
  /// `will_cancel` reports whether the configured synchronous policy blocks it.
  ResourceRequested(
    url~ : String,
    request_method~ : String,
    will_cancel~ : Bool
  )
  RendererProcessTerminated(
    url~ : String,
    status~ : Int32,
    error_code~ : Int32,
    detail~ : String
  )
} derive(Debug, Eq)

///|
pub extend WebContentsEvent with Eq::{not_equal, equal}

///|
pub extend WebContentsEvent with Debug::{to_repr}

///|
/// Why a renderer process disappeared, following Electron's
/// `RenderProcessGoneDetails.reason`.
///
/// CEF reports renderer termination as a status value, so Proton names the
/// statuses instead of passing the raw number. Electron additionally
/// distinguishes `clean-exit` and `memory-eviction`, which CEF does not report
/// as renderer termination.
pub(all) enum RenderProcessGoneReason {
  /// The renderer exited with a non-zero status (`abnormal-exit`).
  AbnormalExit
  /// The renderer was killed, for example by SIGKILL or a task manager
  /// (`killed`).
  Killed
  /// The renderer crashed, for example on a segmentation fault (`crashed`).
  Crashed
  /// The renderer ran out of memory (`oom`).
  OutOfMemory
  /// The renderer process never launched (`launch-failed`).
  LaunchFailed
  /// The platform terminated the renderer for failing code integrity checks
  /// (`integrity-failure`).
  IntegrityFailure
  /// The platform reported a termination status Proton does not name yet.
  Unknown
} derive(Debug, Eq)

///|
pub extend RenderProcessGoneReason with Eq::{not_equal, equal}

///|
pub extend RenderProcessGoneReason with Debug::{to_repr}

///|
/// One renderer termination, following Electron's `RenderProcessGoneDetails`.
pub(all) struct RenderProcessGoneDetails {
  /// Why the renderer disappeared.
  reason : RenderProcessGoneReason
  /// The platform exit code of the terminated renderer.
  exit_code : Int32
} derive(Debug, Eq)

///|
pub extend RenderProcessGoneDetails with Eq::{not_equal, equal}

///|
pub extend RenderProcessGoneDetails with Debug::{to_repr}

///|
/// The application session Proton created for this run, corresponding to
/// Electron's `session-created` argument.
///
/// Proton runs one session per application, so the event fires once during
/// startup. Session operations stay on `WebContentsHandle::session()`, which is
/// backed by the same request context.
pub(all) struct ApplicationSession {
  /// The partition configured with `App::session_partition`, or `None` for the
  /// default session.
  partition : String?
  /// The session data directory, or `None` when this run uses a temporary
  /// profile because Proton does not own the application's single-instance
  /// route.
  data_path : String?
} derive(Debug, Eq)

///|
pub extend ApplicationSession with Eq::{not_equal, equal}

///|
pub extend ApplicationSession with Debug::{to_repr}

///|
/// How the browser reached one navigation-history entry, following Chromium's
/// page-transition types, which Electron reports as `transitionType`.
pub(all) enum NavigationTransition {
  Link
  Typed
  AutoBookmark
  AutoSubframe
  ManualSubframe
  Generated
  /// Chromium's deprecated auto-toplevel transition.
  AutoToplevel
  FormSubmit
  Reload
  Keyword
  KeywordGenerated
  /// A transition type this Proton release does not name.
  Other(Int32)
} derive(Debug, Eq)

///|
pub extend NavigationTransition with Eq::{not_equal, equal}

///|
pub extend NavigationTransition with Debug::{to_repr}

///|
/// Extra context Chromium recorded for a navigation entry, corresponding to
/// Electron's transition qualifiers.
pub(all) enum NavigationTransitionQualifier {
  /// The page redirected the navigation itself.
  ClientRedirect
  /// A server response redirected the navigation.
  ServerRedirect
  /// The entry was reached through back or forward.
  ForwardBack
  /// The entry came from a user-typed address.
  FromAddressBar
} derive(Debug, Eq)

///|
pub extend NavigationTransitionQualifier with Eq::{not_equal, equal}

///|
pub extend NavigationTransitionQualifier with Debug::{to_repr}

///|
/// One entry of a browser's session history, corresponding to Electron's
/// `NavigationEntry`.
pub(all) struct NavigationEntry {
  url : String
  /// Chromium's display-friendly version of `url`.
  display_url : String
  /// The URL the user entered before any redirects.
  original_url : String
  title : String
  transition : NavigationTransition
  transition_qualifiers : Array[NavigationTransitionQualifier]
  has_post_data : Bool
  http_status_code : Int32
} derive(Debug, Eq)

///|
pub extend NavigationEntry with Eq::{not_equal, equal}

///|
pub extend NavigationEntry with Debug::{to_repr}

///|
/// A snapshot of one browser's session history, corresponding to Electron's
/// `webContents.navigationHistory`.
///
/// Chromium keeps one history per tab, so the snapshot belongs to the browser
/// that produced it; `ApplicationContext` navigation elsewhere replaces it.
pub(all) struct NavigationHistory {
  entries : Array[NavigationEntry]
  /// Index of the active entry, or `-1` while the browser has none.
  active_index : Int32
} derive(Debug, Eq)

///|
pub extend NavigationHistory with Eq::{not_equal, equal}

///|
pub extend NavigationHistory with Debug::{to_repr}

///|
priv enum BridgeRequestLifecycleState {
  Running = 0
  Responding = 1
  Completed = 2
  Cancelled = 3
  Stale = 4
} derive(Eq)

///|
priv struct AppLifecycle {
  mut state : AppLifecycleState
}

///|
/// One cookie returned by the browser session.
pub(all) struct Cookie {
  name : String
  value : String
  domain : String
  path : String
  secure : Bool
  http_only : Bool
  same_site : CookieSameSite
  expiration_date : Double?
} derive(Debug, Eq)

///|
pub extend Cookie with Eq::{not_equal, equal}

///|
pub extend Cookie with Debug::{to_repr}

///|
/// Failures while resolving and validating an application's configuration.
pub(all) suberror AppConfigurationError {
  InvalidSetting(name~ : String, message~ : String)
  ExtensionDependencyCycle(extension_id~ : String)
  ExtensionUnavailable(
    extension_id~ : String,
    requested_by~ : String?,
    state~ : String
  )
  ExtensionAdaptationFailed(
    extension_id~ : String,
    error~ : @proton_extension.ExtensionAdapterError
  )
  InvalidJavaScriptNamespace(js_namespace~ : String)
  InvalidJavaScriptApi(js_namespace~ : String, api_name~ : String)
  InvalidEntryUrl(url~ : String, reason~ : String)
  InvalidRendererCapability(detail~ : String)
} derive(Debug)

///|
/// Failures from application-level desktop and process controls.
pub(all) suberror AppControlError {
  InvalidProtocolScheme(scheme~ : String)
  UndeclaredProtocolScheme(scheme~ : String)
  InvalidExecutable(path~ : String)
  /// The current platform does not implement this operation. Electron's
  /// `app` object omits the same methods outside macOS.
  UnsupportedPlatform(action~ : String)
  NativeControlFailure(action~ : String, status~ : Int32, detail~ : String)
} derive(Debug, Eq)

///|
pub extend AppControlError with Eq::{not_equal, equal}

///|
pub extend AppControlError with Debug::{to_repr}

///|
pub extend AppConfigurationError with Debug::{to_repr}

///|
/// Failures while loading the application's initial document.
pub(all) suberror AppEntryError {
  ReadFailed(path~ : String, detail~ : String)
  PlatformLoad(action~ : String, status~ : Int32, detail~ : String)
  ClosedDuringStartup
} derive(Debug)

///|
pub extend AppEntryError with Debug::{to_repr}

///|
/// Failures while starting or stopping command extensions.
pub(all) suberror CommandExtensionLifecycleError {
  ApplicationRegistrationFailed(detail~ : String)
  RegistrationFailed(extension_id~ : String, detail~ : String)
  EventSourceStartFailed(extension_id~ : String, detail~ : String)
  DestroyFailed(extension_id~ : String, detail~ : String)
} derive(Debug)

///|
pub extend CommandExtensionLifecycleError with Debug::{to_repr}

///|
/// Failures produced by application or window lifecycle hooks.
pub(all) suberror LifecycleHookError {
  ApplicationStart(index~ : Int32, detail~ : String)
  ApplicationShutdown(detail~ : String)
  WindowReady(index~ : Int32, detail~ : String)
  WindowClose(window~ : String, detail~ : String)
} derive(Debug)

///|
pub extend LifecycleHookError with Debug::{to_repr}

///|
/// A failure from one stage of best-effort application teardown.
pub(all) suberror AppCleanupError {
  CommandExtension(CommandExtensionLifecycleError)
  LifecycleHook(LifecycleHookError)
  WindowDestroy(status~ : Int32, detail~ : String)
  RuntimeDestroy(status~ : Int32, detail~ : String)
} derive(Debug)

///|
pub extend AppCleanupError with Debug::{to_repr}

///|
/// Failures produced while configuring, starting, or running an application.
pub(all) suberror AppRunError {
  EventLoopError(String)
  ConfigurationError(AppConfigurationError)
  LoggingInitializationFailed(detail~ : String)
  UnsupportedNativeFeature(feature~ : String)
  RuntimeOperationFailed(action~ : String, status~ : Int32, detail~ : String)
  CommandExtensionLifecycleError(CommandExtensionLifecycleError)
  LifecycleHookError(LifecycleHookError)
  EntryLoadError(AppEntryError)
  BridgeStartupError(BridgeDiagnostic)
  BridgeRuntimeError(BridgeDiagnostic)
  CleanupFailed(primary~ : String?, failures~ : Array[AppCleanupError])
  UnexpectedTaskFailure(detail~ : String)
} derive(Debug)

///|
pub extend AppRunError with Debug::{to_repr}