import { _setSecret, _getSecret, _deleteSecret, _isKeyringAvailable } from "agency-lang/stdlib-lib/keyring.js"

/** @module
  @summary Store and retrieve secrets in the system keyring.
  Store and retrieve secrets in the operating system's keyring, so API keys
  and tokens can be stored without plaintext credential files.

  ```ts
  import { setSecret, getSecret, deleteSecret, isKeyringAvailable } from "std::auth/keyring"

  node main() {
    if (isKeyringAvailable()) {
      setSecret("my-api-key", "sk-abc123")
      const key = getSecret("my-api-key")
      print(key)
      deleteSecret("my-api-key")
    }
  }
  ```

  On macOS this uses the Keychain, and on Linux the Secret Service. Windows is
  not yet supported, so fall back to environment variables there. Secrets live
  under the "agency-lang" service name unless you pass a custom `service`.
*/

@always(service, key)
effect std::setSecret { key: string, service: string }
@always(service, key)
effect std::getSecret { key: string, service: string }
@always(service, key)
effect std::deleteSecret { key: string, service: string }

@capabilities(subprocess)
export def setSecret(key: string, value: string, service: string = "agency-lang"): Result raises <std::setSecret> {
  """
  Store a secret in the system keyring, replacing any existing value.

  @param key - A non-empty name identifying the secret within its service.
  @param value - The non-empty secret to store.
  @param service - The namespace shared by calls that store and retrieve this secret.
  """
  return interrupt std::setSecret("Are you sure you want to store a secret in the system keyring?", {
    key: key,
    service: service
  })

  destructive {
    return try _setSecret(key, value, service)
  }
}

@capabilities(subprocess)
export def getSecret(key: string, service: string = "agency-lang"): Result raises <std::getSecret> {
  """
  Retrieve a secret from the system keyring, or null when it is missing.

  @param key - The name used when storing the secret.
  @param service - The namespace used when storing the secret.
  """
  return interrupt std::getSecret("Are you sure you want to read a secret from the system keyring?", {
    key: key,
    service: service
  })

  return try _getSecret(key, service)
}

@capabilities(subprocess)
export def deleteSecret(key: string, service: string = "agency-lang"): Result raises <std::deleteSecret> {
  """
  Delete a secret from the system keyring, returning whether it existed.

  @param key - The name used when storing the secret.
  @param service - The namespace used when storing the secret.
  """
  return interrupt std::deleteSecret("Are you sure you want to delete a secret from the system keyring?", {
    key: key,
    service: service
  })

  destructive {
    return try _deleteSecret(key, service)
  }
}

/**
  Checks whether macOS `security` or Linux `secret-tool` can run.
  A successful check does not guarantee access to a stored secret.
*/
@capabilities(subprocess)
export def isKeyringAvailable(): boolean {
  """
  Check whether this platform has a supported keyring command available.
  """
  return _isKeyringAvailable()
}
