export class InvalidApiKeyOwnerError extends Error {
  override readonly name = 'InvalidApiKeyOwnerError'
  readonly code = 'INVALID_API_KEY_OWNER' as const

  constructor(readonly owner: string) {
    super('issueApiKey: owner must be a non-empty string')
  }
}

export class InvalidApiKeyScopesError extends Error {
  override readonly name = 'InvalidApiKeyScopesError'
  readonly code = 'INVALID_API_KEY_SCOPES' as const

  constructor() {
    super('issueApiKey: scopes must contain only non-empty strings')
  }
}

export class ApiKeyOwnerMismatchError extends Error {
  override readonly name = 'ApiKeyOwnerMismatchError'
  readonly code = 'API_KEY_OWNER_MISMATCH' as const

  constructor(
    readonly owner: string,
    readonly issuedByOwner: string,
  ) {
    super('issueApiKey: owner must match the authenticated issuer')
  }
}

export class ApiKeyRevokedError extends Error {
  override readonly name = 'ApiKeyRevokedError'
  readonly code = 'API_KEY_REVOKED' as const

  constructor(readonly id: string) {
    super('verifyApiKey: key is revoked')
  }
}

export class ApiKeyExpiredError extends Error {
  override readonly name = 'ApiKeyExpiredError'
  readonly code = 'API_KEY_EXPIRED' as const

  constructor(readonly id: string) {
    super('verifyApiKey: key is expired')
  }
}

export class ApiKeyLastUsedAtUpdateError extends Error {
  override readonly name = 'ApiKeyLastUsedAtUpdateError'
  readonly code = 'API_KEY_LAST_USED_AT_UPDATE_FAILED' as const

  constructor(
    readonly id: string,
    readonly cause: unknown,
  ) {
    super('verifyApiKey: lastUsedAt update failed')
  }
}

export type ApiKeyError =
  | InvalidApiKeyOwnerError
  | InvalidApiKeyScopesError
  | ApiKeyOwnerMismatchError
  | ApiKeyRevokedError
  | ApiKeyExpiredError
  | ApiKeyLastUsedAtUpdateError

export function isInvalidApiKeyOwnerError(error: unknown): error is InvalidApiKeyOwnerError {
  return (
    typeof error === 'object' &&
    error !== null &&
    (error as { name?: unknown }).name === 'InvalidApiKeyOwnerError' &&
    (error as { code?: unknown }).code === 'INVALID_API_KEY_OWNER'
  )
}

export function isInvalidApiKeyScopesError(error: unknown): error is InvalidApiKeyScopesError {
  return (
    typeof error === 'object' &&
    error !== null &&
    (error as { name?: unknown }).name === 'InvalidApiKeyScopesError' &&
    (error as { code?: unknown }).code === 'INVALID_API_KEY_SCOPES'
  )
}

export function isApiKeyOwnerMismatchError(error: unknown): error is ApiKeyOwnerMismatchError {
  return (
    typeof error === 'object' &&
    error !== null &&
    (error as { name?: unknown }).name === 'ApiKeyOwnerMismatchError' &&
    (error as { code?: unknown }).code === 'API_KEY_OWNER_MISMATCH'
  )
}

export function isApiKeyRevokedError(error: unknown): error is ApiKeyRevokedError {
  return (
    typeof error === 'object' &&
    error !== null &&
    (error as { name?: unknown }).name === 'ApiKeyRevokedError' &&
    (error as { code?: unknown }).code === 'API_KEY_REVOKED'
  )
}

export function isApiKeyExpiredError(error: unknown): error is ApiKeyExpiredError {
  return (
    typeof error === 'object' &&
    error !== null &&
    (error as { name?: unknown }).name === 'ApiKeyExpiredError' &&
    (error as { code?: unknown }).code === 'API_KEY_EXPIRED'
  )
}

export function isApiKeyLastUsedAtUpdateError(
  error: unknown,
): error is ApiKeyLastUsedAtUpdateError {
  return (
    typeof error === 'object' &&
    error !== null &&
    (error as { name?: unknown }).name === 'ApiKeyLastUsedAtUpdateError' &&
    (error as { code?: unknown }).code === 'API_KEY_LAST_USED_AT_UPDATE_FAILED'
  )
}

export function isApiKeyError(error: unknown): error is ApiKeyError {
  return (
    isInvalidApiKeyOwnerError(error) ||
    isInvalidApiKeyScopesError(error) ||
    isApiKeyOwnerMismatchError(error) ||
    isApiKeyRevokedError(error) ||
    isApiKeyExpiredError(error) ||
    isApiKeyLastUsedAtUpdateError(error)
  )
}
