use thiserror::Error;

#[derive(Debug, Error)]
pub enum RegistryError {
    #[error(transparent)]
    Storage(#[from] sqlx::Error),
    #[error(transparent)]
    Serialization(#[from] serde_json::Error),
    #[error("workspace {workspace_id} was not found")]
    WorkspaceNotFound { workspace_id: String },
    #[error("workspace with slug {slug} already exists")]
    WorkspaceSlugAlreadyExists { slug: String },
    #[error("user {user_id} was not found")]
    UserNotFound { user_id: String },
    #[error("user with email {email} already exists")]
    UserEmailAlreadyExists { email: String },
    #[error("membership for user {user_id} in workspace {workspace_id} was not found")]
    MembershipNotFound {
        workspace_id: String,
        user_id: String,
    },
    #[error("invitation {invitation_id} was not found")]
    InvitationNotFound { invitation_id: String },
    #[error("platform api key {key_id} was not found")]
    PlatformApiKeyNotFound { key_id: String },
    #[error("secret {secret_id} was not found")]
    SecretNotFound { secret_id: String },
    #[error("stream session {session_id} was not found")]
    StreamSessionNotFound { session_id: String },
    #[error("async job {job_id} was not found")]
    AsyncJobNotFound { job_id: String },
    #[error("invalid stream session transition for {session_id}: {from} -> {to}")]
    InvalidStreamSessionTransition {
        session_id: String,
        from: String,
        to: String,
    },
    #[error("invalid async job transition for {job_id}: {from} -> {to}")]
    InvalidAsyncJobTransition {
        job_id: String,
        from: String,
        to: String,
    },
    #[error("secret with name {name} already exists in workspace {workspace_id}")]
    SecretNameAlreadyExists { workspace_id: String, name: String },
    #[error("secret {secret_id} is referenced by auth profile {auth_profile_id}")]
    SecretReferencedByAuthProfile {
        secret_id: String,
        auth_profile_id: String,
    },
    #[error("invocation log {log_id} was not found")]
    InvocationLogNotFound { log_id: String },
    #[error("agent {agent_id} was not found")]
    AgentNotFound { agent_id: String },
    #[error("published agent {workspace_slug}/{agent_slug} was not found")]
    PublishedAgentNotFound {
        workspace_slug: String,
        agent_slug: String,
    },
    #[error("operation {operation_id} already exists")]
    OperationAlreadyExists { operation_id: String },
    #[error("operation {operation_id} was not found")]
    OperationNotFound { operation_id: String },
    #[error("operation version {version} for {operation_id} was not found")]
    OperationVersionNotFound { operation_id: String, version: u32 },
    #[error("operation {operation_id} cannot be deleted while it is bound to a published agent")]
    OperationHasPublishedAgentBindings { operation_id: String },
    #[error("operation {operation_id} must start with version 1, got {version}")]
    InvalidInitialVersion { operation_id: String, version: u32 },
    #[error("operation {operation_id} expected next version {expected}, got {actual}")]
    InvalidVersionSequence {
        operation_id: String,
        expected: u32,
        actual: u32,
    },
    #[error("operation {operation_id} changed immutable field {field}")]
    ImmutableOperationFieldChanged {
        operation_id: String,
        field: &'static str,
    },
    #[error("auth profile {auth_profile_id} was not found")]
    AuthProfileNotFound { auth_profile_id: String },
    #[error("yaml import job {job_id} was not found")]
    YamlImportJobNotFound { job_id: String },
    #[error("unsupported enum representation for field {field}")]
    InvalidEnumRepresentation { field: &'static str },
    #[error("invalid numeric value for field {field}: {value}")]
    InvalidNumericValue { field: &'static str, value: i64 },
}
