/// Concurrent ownership of one home conflicts with the one-daemon E2E harness.
import albedo/daemon/server
import gleam/erlang/process
import gleam/result
import gleeunit/should

@external(erlang, "albedo_skills_test_support", "fixture")
fn fixture() -> #(String, String, String)

@external(erlang, "albedo_skills_test_support", "cleanup")
fn cleanup(root: String) -> Nil

pub fn second_daemon_cannot_claim_a_held_home_test() -> Nil {
  let #(root, _, home) = fixture()
  let claimed = process.new_subject()
  // A subject only delivers to the process that created it, so the owner makes
  // its own release subject and hands it back.
  process.spawn(fn() {
    let release = process.new_subject()
    process.send(claimed, #(server.claim_home(home), release))
    process.receive_forever(release)
  })
  let assert Ok(#(first, release)) = process.receive(claimed, 5000)
  first |> should.equal(Ok(Nil))

  server.claim_home(home)
  |> result.map_error(fn(_) { Nil })
  |> should.equal(Error(Nil))

  // The connection closes when the owner's resources are freed, which can land
  // just after its exit is observable, so a fresh claimant retries briefly.
  process.send(release, Nil)
  claim_eventually(home, 50) |> should.equal(Ok(Nil))

  cleanup(root)
}

fn claim_eventually(home: String, attempts: Int) -> Result(Nil, Nil) {
  let reply = process.new_subject()
  process.spawn(fn() { process.send(reply, server.claim_home(home)) })
  case process.receive(reply, 5000) {
    Ok(Ok(Nil)) -> Ok(Nil)
    _ if attempts > 1 -> {
      process.sleep(20)
      claim_eventually(home, attempts - 1)
    }
    _ -> Error(Nil)
  }
}
