// AT-identifier -- "a DID or a handle", the type of every `actor`, `repo` and
// `identifier` parameter in the protocol.
//
// https://atproto.com/specs/at-uri-scheme
// Ported from @atproto/syntax packages/syntax/src/at-identifier.ts.
//
// A sum type rather than a validated string, because the two halves behave
// differently and the difference matters at every call site: a DID is stable
// and a handle is not, so code that caches, keys or compares must know which
// one it has. Upstream models this as a union of two branded strings and then
// re-tests the prefix wherever it needs to know; here the answer is in the
// value.

///|
pub(all) enum AtIdentifier {
  Did(Did)
  Handle(Handle)
} derive(Eq, Debug)

///|
pub impl Show for AtIdentifier with fn output(self, logger) {
  logger.write_string(self.to_string())
}

///|
pub fn AtIdentifier::to_string(self : Self) -> String {
  match self {
    Did(d) => d.to_string()
    Handle(h) => h.to_string()
  }
}

///|
/// The DID, if this is one. `None` for a handle -- resolving a handle to a DID
/// needs the network and is a client call, not a syntax operation.
pub fn AtIdentifier::as_did(self : Self) -> Did? {
  match self {
    Did(d) => Some(d)
    Handle(_) => None
  }
}

///|
pub fn AtIdentifier::as_handle(self : Self) -> Handle? {
  match self {
    Did(_) => None
    Handle(h) => Some(h)
  }
}

///|
pub fn AtIdentifier::is_valid(input : String) -> Bool {
  try {
    AtIdentifier::parse(input) |> ignore
    true
  } catch {
    _ => false
  }
}

///|
/// The `did:` prefix decides which validator runs, so a malformed DID is
/// reported as a bad DID rather than as a bad handle -- `did:thing` is not a
/// handle that happens to contain a colon.
pub fn AtIdentifier::parse(input : String) -> AtIdentifier raise SyntaxError {
  if input.has_prefix("did:") {
    Did(Did::parse(input))
  } else {
    Handle(Handle::parse(input))
  }
}