///|
fn moon_binding_app_command(app_type : String) -> String? {
  match app_type {
    "claude" => Some("claude")
    "codex" => Some("codex")
    "gemini" => Some("gemini")
    "opencode" => Some("opencode")
    "openclaw" => Some("openclaw")
    "hermes" => Some("hermes")
    _ => None
  }
}

///|
fn moon_binding_provider_app_type(app_type : String) -> String {
  if app_type == "moondesk" || app_type == "moonclaw" {
    "openclaw"
  } else {
    app_type
  }
}

///|
fn moon_binding_moondesk_workspace_root() -> String {
  let suite_root = (@os.getenv("MOONSUITE_WORKSPACE_ROOT") catch { _ => None })
    .unwrap_or("")
    .trim()
    .to_owned()
  let configured = if suite_root != "" {
    suite_root
  } else {
    (@os.getenv("MOONDESK_WORKSPACE_ROOT") catch { _ => None })
    .unwrap_or("")
    .trim()
    .to_owned()
  }
  if configured != "" {
    return @pathx.normalize(configured)
  }
  let home = moon_home_dir()
  @pathx.join(
    home, "Library/Application Support/app.vectie.moondesk.lepusa.live/workspace",
  )
}

///|
fn moon_binding_moondesk_service_path(root : String) -> String {
  @moonsuite.product_home_for_workspace_root(root, "moonclaw").service_path
}

///|
fn moon_binding_moondesk_provider_path(root : String) -> String {
  default_moongate_moonclaw_providers_file_path_for_workspace_root(root)
}

///|
fn moon_binding_moonclaw_config_path(root : String) -> String {
  @moonsuite.product_artifact_for_workspace_root(
    root, "moonclaw", "moonclaw.json",
  )
}

///|
async fn moon_binding_moonclaw_initialized(root : String) -> Bool {
  let text = @fsx.read_file(moon_binding_moonclaw_config_path(root)) catch {
    _ => return false
  }
  let json = @json.parse(text) catch { _ => return false }
  guard json is Object(obj) else { return false }
  obj.get("agents") is Some(Object(_)) && obj.get("gateway") is Some(Object(_))
}

///|
async fn moon_binding_moondesk_service_configured(root : String) -> Bool {
  let text = @fsx.read_file(moon_binding_moondesk_service_path(root)) catch {
    _ => return false
  }
  let json = @json.parse(text) catch { _ => return false }
  guard json is Object(obj) else { return false }
  guard obj.get("daemon") is Some(Object(daemon)) else { return false }
  json_string_from_map(daemon, "command").unwrap_or("").trim() != ""
}

///|
async fn moon_binding_existing_moondesk_runtime(
  root : String,
) -> (String, Array[String], String)? {
  let text = @fsx.read_file(moon_binding_moondesk_service_path(root)) catch {
    _ => return None
  }
  let json = @json.parse(text) catch { _ => return None }
  guard json is Object(obj) else { return None }
  guard obj.get("daemon") is Some(Object(daemon)) else { return None }
  let command = json_string_from_map(daemon, "command")
    .unwrap_or("")
    .trim()
    .to_owned()
  if command == "" || !@fsx.exists_as_file(command) {
    return None
  }
  let args : Array[String] = []
  match daemon.get("args") {
    Some(Array(items)) =>
      for item in items {
        match item {
          String(value) => args.push(value)
          _ => return None
        }
      }
    _ => return None
  }
  let cwd = json_string_from_map(obj, "cwd").unwrap_or(root).trim().to_owned()
  Some((command, args, if cwd == "" { root } else { cwd }))
}

///|
async fn moon_binding_moondesk_manifest_matches(
  root : String,
  base_url : String,
  model : String,
) -> Bool {
  let text = @fsx.read_file(moon_binding_moondesk_provider_path(root)) catch {
    _ => return false
  }
  let json = @json.parse(text) catch { _ => return false }
  guard json is Object(obj) else { return false }
  guard obj.get("providers") is Some(Object(providers)) else { return false }
  guard providers.get("moongate") is Some(Object(provider)) else {
    return false
  }
  if json_string_from_map(provider, "baseUrl") != Some(base_url) {
    return false
  }
  guard provider.get("models") is Some(Array(models)) else { return false }
  models.any(item => {
    guard item is Object(model_obj) else { false }
    json_string_from_map(model_obj, "id") == Some(model)
  })
}

///|
async fn moon_binding_moongate_provider_exists(root : String) -> Bool {
  let text = @fsx.read_file(moon_binding_moondesk_provider_path(root)) catch {
    _ => return false
  }
  let json = @json.parse(text) catch { _ => return false }
  guard json is Object(obj) else { return false }
  guard obj.get("providers") is Some(Object(providers)) else { return false }
  providers.get("moongate") is Some(Object(_))
}

///|
async fn moon_binding_write_moondesk_provider(
  root : String,
  host : String,
  port : Int,
  model : String,
) -> Result[String, String] {
  let path = moon_binding_moondesk_provider_path(root)
  let existing = @fsx.read_file(path) catch { _ => "" }
  let json = @json.parse(existing) catch { _ => Json::object({}) }
  let obj = match json {
    Object(obj) => obj
    _ => {}
  }
  let providers = match obj.get("providers") {
    Some(Object(providers)) => providers
    _ => {}
  }
  guard moongate_moonclaw_providers_file_json(host~, port~, model~)
    is { "providers": { "moongate": provider, .. }, .. } else {
    return Err("moondesk_provider_manifest_invalid")
  }
  providers["moongate"] = provider
  obj["providers"] = Json::object(providers)
  @fsx.make_directory(@pathx.dirname(path), recursive=true, exists_ok=true) catch {
    error => return Err("Could not prepare MoonDesk provider folder: \{error}")
  }
  atomic_write_store_file(path, Json::object(obj).stringify(indent=2) + "\n") catch {
    error => return Err("Could not write MoonDesk provider manifest: \{error}")
  }
  Ok(path)
}

///|
async fn moon_binding_write_moondesk_service(
  root : String,
) -> Result[String, String] {
  let existing_runtime = moon_binding_existing_moondesk_runtime(root)
  let moonclaw_root = (@os.getenv("MOONCLAW_ROOT") catch { _ => None })
    .unwrap_or("")
    .trim()
    .to_owned()
  let (command, args, cwd) = match existing_runtime {
    Some((command, args, cwd)) => (command, args, cwd)
    None =>
      if moonclaw_root != "" &&
        @fsx.exists(@pathx.join(moonclaw_root, "moon.mod")) {
        let local_moon = @pathx.join(moon_home_dir(), ".moon/bin/moon")
        (
          if @fsx.exists(local_moon) {
            local_moon
          } else {
            "moon"
          },
          ["run", "cmd/main", "--", "daemon", "--port", "0", "--serve", root],
          moonclaw_root,
        )
      } else {
        let probe = moon_single_tool_version_json("moonclaw")
        if json_string_field(probe, "version") is None {
          return Err(
            "MoonClaw is not installed in MoonDesk and was not found on PATH",
          )
        }
        ("moonclaw", ["daemon", "--port", "0", "--serve", root], root)
      }
  }
  let path = moon_binding_moondesk_service_path(root)
  let existing = @fsx.read_file(path) catch { _ => "" }
  let json = @json.parse(existing) catch { _ => Json::object({}) }
  let obj = match json {
    Object(obj) => obj
    _ => {}
  }
  obj["kind"] = Json::string("moondesk-moonclaw-service.v1")
  obj["cwd"] = Json::string(cwd)
  obj["daemon"] = {
    "command": Json::string(command),
    "args": Json::array(args.map(value => Json::string(value))),
  }.to_json()
  @fsx.make_directory(@pathx.dirname(path), recursive=true, exists_ok=true) catch {
    error => return Err("Could not prepare MoonDesk service folder: \{error}")
  }
  atomic_write_store_file(path, Json::object(obj).stringify(indent=2) + "\n") catch {
    error => return Err("Could not write MoonDesk service config: \{error}")
  }
  Ok(path)
}

///|
async fn moon_binding_remove_moondesk_provider(
  root : String,
) -> Result[Unit, String] {
  let path = moon_binding_moondesk_provider_path(root)
  let text = @fsx.read_file(path) catch { _ => return Ok(()) }
  let json = @json.parse(text) catch {
    _ => return Err("MoonDesk provider manifest is invalid")
  }
  guard json is Object(obj) else {
    return Err("MoonDesk provider manifest is invalid")
  }
  guard obj.get("providers") is Some(Object(providers)) else { return Ok(()) }
  providers.remove("moongate")
  obj["providers"] = Json::object(providers)
  atomic_write_store_file(path, Json::object(obj).stringify(indent=2) + "\n") catch {
    error => return Err("Could not update MoonDesk provider manifest: \{error}")
  }
  Ok(())
}

///|
fn moon_binding_codex_app_bundle_paths(
  home : String,
  system_applications : String,
) -> Array[String] {
  let user_applications = @pathx.join(home, "Applications")
  [
    @pathx.join(system_applications, "ChatGPT.app"),
    @pathx.join(system_applications, "Codex.app"),
    @pathx.join(user_applications, "ChatGPT.app"),
    @pathx.join(user_applications, "Codex.app"),
  ]
}

///|
fn moon_binding_codex_bundled_executable_paths(
  home : String,
  system_applications : String,
) -> Array[String] {
  moon_binding_codex_app_bundle_paths(home, system_applications).map(app => {
    @pathx.join(app, "Contents/Resources/codex")
  })
}

///|
fn moon_binding_codex_state_paths(home : String) -> Array[String] {
  [
    @pathx.join(home, ".codex"),
    @pathx.join(home, "Library/Application Support/Codex"),
    @pathx.join(home, "Library/Application Support/OpenAI/Codex"),
  ]
}

///|
async fn moon_binding_any_path_exists(paths : Array[String]) -> Bool {
  for path in paths {
    if @fsx.exists(path) {
      return true
    }
  }
  false
}

///|
async fn moon_binding_codex_installation_json() -> Json {
  let command_probe = moon_single_tool_version_json("codex")
  let command_version = json_string_field(command_probe, "version")
  if command_version is Some(version) &&
    !json_bool_field(command_probe, "installed_but_broken").unwrap_or(false) {
    return {
      "installed": Json::boolean(true),
      "version": Json::string(version),
      "error": Json::null(),
    }.to_json()
  }
  let home = moon_home_dir()
  for path in moon_binding_codex_bundled_executable_paths(home, "/Applications") {
    if @fsx.exists_as_file(path) {
      match moon_probe_tool_version_at(path) {
        Some(version) =>
          return {
            "installed": Json::boolean(true),
            "version": Json::string(version),
            "error": Json::null(),
          }.to_json()
        None => ()
      }
    }
  }
  let installed = moon_binding_any_path_exists(
      moon_binding_codex_app_bundle_paths(home, "/Applications"),
    ) ||
    moon_binding_any_path_exists(moon_binding_codex_state_paths(home))
  {
    "installed": Json::boolean(installed),
    "version": Json::null(),
    "error": if installed {
      Json::null()
    } else {
      match json_string_field(command_probe, "error") {
        Some(error) => Json::string(error)
        None => Json::null()
      }
    },
  }.to_json()
}

///|
async fn moon_binding_app_installation_json(app_type : String) -> Json {
  if app_type == "moonclaw" {
    let root = moon_binding_moondesk_workspace_root()
    let initialized = moon_binding_moonclaw_initialized(root)
    return {
      "installed": Json::boolean(initialized),
      "version": Json::null(),
      "error": if initialized {
        Json::null()
      } else {
        Json::string("Run `moonclaw onboard init` before binding MoonGate")
      },
    }.to_json()
  }
  if app_type == "moondesk" {
    let home_app = @pathx.join(
      @pathx.join(moon_home_dir(), "Applications"),
      "MoonDesk.app",
    )
    let workspace = moon_binding_moondesk_workspace_root()
    let installed = @fsx.exists("/Applications/MoonDesk.app") ||
      @fsx.exists(home_app) ||
      @fsx.exists(workspace)
    return {
      "installed": Json::boolean(installed),
      "version": Json::null(),
      "error": Json::null(),
    }.to_json()
  }
  if app_type == "claude-desktop" {
    let home_app = @pathx.join(
      @pathx.join(moon_home_dir(), "Applications"),
      "Claude.app",
    )
    let installed = @fsx.exists("/Applications/Claude.app") ||
      @fsx.exists(home_app) ||
      moon_config_exists(app_type)
    return {
      "installed": Json::boolean(installed),
      "version": Json::null(),
      "error": Json::null(),
    }.to_json()
  }
  if app_type == "codex" {
    return moon_binding_codex_installation_json()
  }
  guard moon_binding_app_command(app_type) is Some(command) else {
    return {
      "installed": Json::boolean(false),
      "version": Json::null(),
      "error": Json::string("Automatic app detection is unavailable"),
    }.to_json()
  }
  let probe = moon_single_tool_version_json(command)
  {
    "installed": Json::boolean(
      json_string_field(probe, "version") is Some(_) &&
      !json_bool_field(probe, "installed_but_broken").unwrap_or(false),
    ),
    "version": match json_string_field(probe, "version") {
      Some(version) => Json::string(version)
      None => Json::null()
    },
    "error": match json_string_field(probe, "error") {
      Some(error) => Json::string(error)
      None => Json::null()
    },
  }.to_json()
}

///|
fn moon_binding_mode(app_type : String) -> String {
  match app_type {
    "moondesk" | "moonclaw" | "codex" | "claude-desktop" => "automatic"
    _ => "manual"
  }
}

///|
fn ProviderRouteTarget::binding_model(
  self : ProviderRouteTarget,
  fallback : String,
) -> String {
  match self.model_mapping {
    Some(mapping) => mapping.default_model.unwrap_or(fallback)
    None => fallback
  }
}

///|
async fn ProxyService::app_binding_status_json(
  self : ProxyService,
  app_type : String,
  host : String,
  port : Int,
) -> Json {
  let installation = moon_binding_app_installation_json(app_type)
  let installed = json_bool_field(installation, "installed").unwrap_or(false)
  let mode = moon_binding_mode(app_type)
  let provider_app_type = moon_binding_provider_app_type(app_type)
  let current_id = self.provider_router.current_provider_id(provider_app_type)
  let current_provider = match current_id {
    Some(provider_id) =>
      self.provider_router.provider_by_id(provider_app_type, provider_id)
    None => None
  }
  let mut managed = false
  let mut bound = false
  let mut stale = false
  let mut config_path = moon_config_file_path(app_type)
  let mut configured_url : String? = None
  let mut expected_url : String? = None
  match app_type {
    "moondesk" | "moonclaw" => {
      let root = moon_binding_moondesk_workspace_root()
      let expected = "http://\{host}:\{port}/openclaw/v1"
      let model = match current_provider {
        Some(provider) => provider.binding_model(@suite.default_model())
        None => @suite.default_model()
      }
      let manifest_path = moon_binding_moondesk_provider_path(root)
      managed = moon_binding_moongate_provider_exists(root)
      bound = moon_binding_moonclaw_initialized(root) &&
        moon_binding_moondesk_manifest_matches(root, expected, model) &&
        (
          app_type == "moonclaw" ||
          moon_binding_moondesk_service_configured(root)
        )
      stale = managed && !bound
      config_path = manifest_path
      configured_url = if managed { Some(expected) } else { None }
      expected_url = Some(expected)
    }
    "codex" => {
      let status = @codex_config.status()
      let expected = "http://{host}:{port}/v1"
      managed = status.configured
      bound = status.configured && status.base_url == Some(expected)
      stale = status.configured && !bound
      config_path = status.config_path
      configured_url = status.base_url
      expected_url = Some(expected)
    }
    "claude-desktop" => {
      let status = @claude_desktop.status()
      let expected = @claude_desktop.local_gateway_base_url(host, port)
      managed = status.configured
      bound = status.configured && status.actual_base_url == Some(expected)
      stale = status.configured && !bound
      config_path = status.profile_path
      configured_url = status.actual_base_url
      expected_url = Some(expected)
    }
    _ => ()
  }
  let state = if !installed {
    "not_installed"
  } else if bound {
    "bound"
  } else if stale {
    "stale"
  } else if mode == "manual" {
    "manual"
  } else {
    "not_bound"
  }
  {
    "appType": Json::string(app_type),
    "installed": Json::boolean(installed),
    "version": match json_string_field(installation, "version") {
      Some(version) => Json::string(version)
      None => Json::null()
    },
    "detectionError": match json_string_field(installation, "error") {
      Some(error) => Json::string(error)
      None => Json::null()
    },
    "bindingMode": Json::string(mode),
    "bindingState": Json::string(state),
    "managedBindingFound": Json::boolean(managed),
    "bound": Json::boolean(bound),
    "configPath": Json::string(config_path),
    "configuredUrl": match configured_url {
      Some(url) => Json::string(url)
      None => Json::null()
    },
    "expectedUrl": match expected_url {
      Some(url) => Json::string(url)
      None => Json::null()
    },
    "currentProviderId": match current_id {
      Some(provider_id) => Json::string(provider_id)
      None => Json::null()
    },
    "currentProviderName": match current_provider {
      Some(provider) => Json::string(provider.provider_name)
      None => Json::null()
    },
  }.to_json()
}

///|
async fn ProxyService::handle_get_app_binding(
  self : ProxyService,
  r : @httpx.RequestReader,
  w : @httpx.ResponseWriter,
  host : String,
  port : Int,
) -> Unit {
  let body = proxy_json_body(r)
  guard provider_app_from_request(r.path, body) is Some(app_type) else {
    write_usage_bad_request(w, "missing_app")
    return
  }
  write_usage_json(w, self.app_binding_status_json(app_type, host, port))
}

///|
async fn ProxyService::handle_bind_app(
  self : ProxyService,
  r : @httpx.RequestReader,
  w : @httpx.ResponseWriter,
  usage : UsageService,
  host : String,
  port : Int,
) -> Unit {
  let body = proxy_json_body(r)
  guard provider_app_from_request(r.path, body) is Some(app_type) else {
    write_usage_bad_request(w, "missing_app")
    return
  }
  if moon_binding_mode(app_type) != "automatic" {
    write_usage_bad_request(w, "manual_binding_required")
    return
  }
  let installation = moon_binding_app_installation_json(app_type)
  if !json_bool_field(installation, "installed").unwrap_or(false) {
    write_usage_bad_request(w, "app_not_installed")
    return
  }
  guard provider_route_provider_id_from_request(r.path, body)
    is Some(provider_id) else {
    write_usage_bad_request(w, "missing_provider_id")
    return
  }
  let provider_app_type = moon_binding_provider_app_type(app_type)
  guard self.provider_router.provider_by_id(provider_app_type, provider_id)
    is Some(provider) else {
    write_usage_bad_request(w, "provider_not_found")
    return
  }
  if !provider.enabled {
    write_usage_bad_request(w, "provider_unavailable")
    return
  }
  let provider_model = provider.binding_model(@suite.default_model())
  if (app_type == "moondesk" || app_type == "moonclaw" || app_type == "codex") &&
    provider_model.trim().is_empty() {
    write_usage_bad_request(w, "provider_model_not_configured")
    return
  }
  let result = match app_type {
    "moondesk" => {
      let root = moon_binding_moondesk_workspace_root()
      match moon_binding_write_moondesk_service(root) {
        Err(error) => Err(error)
        Ok(_) =>
          match
            moon_binding_write_moondesk_provider(
              root, host, port, provider_model,
            ) {
            Ok(_) => Ok(())
            Err(error) => Err(error)
          }
      }
    }
    "moonclaw" => {
      let root = moon_binding_moondesk_workspace_root()
      if !moon_binding_moonclaw_initialized(root) {
        Err("Run `moonclaw onboard init` before binding MoonGate")
      } else {
        match
          moon_binding_write_moondesk_provider(root, host, port, provider_model) {
          Ok(_) => Ok(())
          Err(error) => Err(error)
        }
      }
    }
    "codex" =>
      match @codex_config.install_proxy_config(host, port, provider_model) {
        Ok(_) => Ok(())
        Err(error) => Err(error)
      }
    "claude-desktop" =>
      match @claude_desktop.install_proxy_profile(host, port) {
        Ok(_) => Ok(())
        Err(error) => Err(error)
      }
    _ => Err("manual_binding_required")
  }
  match result {
    Err(error) => {
      write_usage_bad_request(w, error)
      return
    }
    Ok(_) => ()
  }
  self.provider_router.set_current_provider(provider_app_type, provider_id)
  self.proxy_takeover_enabled.set(provider_app_type, true)
  self.proxy_enabled = true
  usage.set_active_target(
    provider_app_type,
    provider_id,
    provider.provider_name,
  )
  if !self.persist_provider_store_or_error(w) {
    return
  }
  if !self.persist_proxy_store_or_error(w) {
    return
  }
  write_usage_json(w, self.app_binding_status_json(app_type, host, port))
}

///|
async fn ProxyService::handle_unbind_app(
  self : ProxyService,
  r : @httpx.RequestReader,
  w : @httpx.ResponseWriter,
  host : String,
  port : Int,
) -> Unit {
  let body = proxy_json_body(r)
  guard provider_app_from_request(r.path, body) is Some(app_type) else {
    write_usage_bad_request(w, "missing_app")
    return
  }
  let result = match app_type {
    "moondesk" | "moonclaw" =>
      moon_binding_remove_moondesk_provider(
        moon_binding_moondesk_workspace_root(),
      )
    "codex" => @codex_config.uninstall_proxy_config()
    "claude-desktop" => @claude_desktop.uninstall_proxy_profile()
    _ => Err("manual_binding_required")
  }
  match result {
    Err(error) => {
      write_usage_bad_request(w, error)
      return
    }
    Ok(_) => ()
  }
  self.proxy_takeover_enabled.set(
    moon_binding_provider_app_type(app_type),
    false,
  )
  if !self.persist_proxy_store_or_error(w) {
    return
  }
  write_usage_json(w, self.app_binding_status_json(app_type, host, port))
}