// Copyright (c) Subzero Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

//! Error types for the Feature Management Program

use rialo_s_instruction::error::InstructionError;
use rialo_s_program_error::{PrintProgramError, ProgramError};

/// Errors that can be returned by the Feature Management Program
///
/// **Stable from this commit forward.** Discriminants surface as
/// `ProgramError::Custom(u32)` over the wire, so reordering or renumbering
/// silently shifts what external decoders see. Pre-launch this enum has
/// been compacted to fill the gaps left by the dropped sticky/windowed
/// variants; from now on, add new variants only at the tail with the next
/// unused discriminant.
#[derive(Debug, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum FeatureManagementError {
    /// Unauthorized access - signature verification failed
    Unauthorized = 0,

    /// Invalid feature name (empty or too long)
    InvalidFeatureName = 1,

    /// Feature not found
    FeatureNotFound = 2,

    /// Serialization error
    SerializationError = 3,

    /// Deserialization error
    DeserializationError = 4,

    /// Invalid instruction data
    InvalidInstructionData = 5,

    /// Internal error (e.g., mutex lock failure)
    InternalError = 6,

    /// Duplicate feature in modification list
    DuplicateFeature = 7,

    /// Invalid storage account (not the expected PDA)
    InvalidStorageAccount = 8,

    /// Storage account already initialized
    AlreadyInitialized = 9,

    /// Storage account not initialized
    NotInitialized = 10,

    /// Maximum feature count exceeded.
    MaxFeatureCountExceeded = 11,

    /// A single `Enable` instruction submitted more names than
    /// `MAX_NAMES_PER_BATCH` permits.
    TooManyNames = 12,

    /// `AcceptAuthorityTransfer` / `CancelAuthorityTransfer` invoked while
    /// no transfer is pending.
    NoPendingTransfer = 13,

    /// `ProposeAuthorityTransfer` invoked while a previous proposal is
    /// still outstanding. Cancel the existing proposal first.
    PendingTransferExists = 14,

    /// `ProposeAuthorityTransfer` invoked with `new_authority` equal to the
    /// current authority. Distinct from `Unauthorized` — the signer IS the
    /// authority; the *target* of the transfer is degenerate.
    InvalidTransferTarget = 15,

    /// `ScheduleEnable` invoked with a `fire_at_ms` at or before the current
    /// block time. A schedule must activate in the future; use `Enable` for
    /// immediate activation.
    ScheduleInPast = 16,

    /// `ScheduleEnable` invoked with a `fire_at_ms` more than
    /// `MAX_SCHEDULE_HORIZON_MS` past the current block time. Guards against
    /// fat-fingered far-future timestamps (e.g. seconds mistaken for millis).
    ScheduleTooFarOut = 17,

    /// `Cancel` invoked with a `request_id` that has no pending entry —
    /// already fired, already cancelled, or never existed.
    RequestNotFound = 18,

    /// `ScheduleEnable` invoked while the pending set is already at
    /// `MAX_PENDING_REQUESTS`. Cancel or let existing schedules fire first.
    TooManyPendingRequests = 19,

    /// `ScheduleEnable` invoked with a `request_id` that already has a pending
    /// entry.
    RequestAlreadyExists = 20,

    /// `ScheduleEnable` whose new pending entry would push the serialized
    /// `FeaturesState` over `MAX_FEATURES_STATE_SIZE`. The byte budget — not
    /// `MAX_PENDING_REQUESTS` — is the binding cap once requests carry
    /// non-trivial batches, so this is surfaced explicitly rather than as a
    /// bare `SerializationError` at save time.
    PendingStateTooLarge = 21,
}

impl From<FeatureManagementError> for ProgramError {
    fn from(e: FeatureManagementError) -> Self {
        ProgramError::Custom(e as u32)
    }
}

impl From<FeatureManagementError> for InstructionError {
    fn from(e: FeatureManagementError) -> Self {
        InstructionError::Custom(e as u32)
    }
}

impl PrintProgramError for FeatureManagementError {
    fn print<E>(&self) {}
}
