use core::{
    fmt::{self, Debug, Formatter},
    ops::Range,
};

/// Interrupt trigger type configuration.
///
/// Defines whether an interrupt is triggered on signal edges or levels.
/// This affects how the GIC samples and processes the interrupt signal.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Trigger {
    /// Edge-triggered interrupt.
    ///
    /// The interrupt is triggered on a rising edge (or falling edge for active-low signals).
    /// The interrupt becomes pending when the signal transitions and remains pending
    /// until software handles it, regardless of the signal's current state.
    Edge,
    /// Level-triggered interrupt.
    ///
    /// The interrupt is triggered when the signal is asserted (high for active-high,
    /// low for active-low). The interrupt remains pending as long as the signal
    /// stays asserted and becomes inactive when the signal is deasserted.
    Level,
}

/// Configuration for setting up an interrupt.
///
/// Contains all necessary information to configure an interrupt in the GIC,
/// including its ID and trigger behavior.
///
/// # Examples
///
/// ```
/// use arm_gic_driver::{IntId, IrqConfig, Trigger};
///
/// let config = IrqConfig {
///     id: IntId::spi(42),
///     trigger: Trigger::Level,
/// };
/// ```
#[derive(Debug, Clone)]
pub struct IrqConfig {
    /// The interrupt ID to configure
    pub id: IntId,
    /// The trigger type for this interrupt
    pub trigger: Trigger,
}

/// Interrupt ID range for Software Generated Interrupts (SGIs).
///
/// SGI is an interrupt generated by software writing to a GICD_SGIR register in
/// the GIC. The system uses SGIs for interprocessor communication.
/// Range: 0-15 (16 interrupts total)
pub const SGI_RANGE: Range<u32> = Range { start: 0, end: 16 };

/// Interrupt ID range for Private Peripheral Interrupts (PPIs).
///
/// PPI is a peripheral interrupt that is specific to a single processor.
/// Each CPU core has its own set of PPIs that cannot be routed to other cores.
/// Range: 16-31 (16 interrupts total)
pub const PPI_RANGE: Range<u32> = Range { start: 16, end: 32 };

/// Interrupt ID range for Shared Peripheral Interrupts (SPIs).
///
/// SPI is a peripheral interrupt that the Distributor can route to any of a
/// specified combination of processors. These are used for system-wide peripherals.
/// Range: 32-1019 (988 interrupts total)
pub const SPI_RANGE: Range<u32> = Range {
    start: 32,
    end: 1020,
};

/// Interrupt ID range for special interrupt IDs.
///
/// These interrupt IDs are reserved for special purposes and are not
/// used for regular interrupt handling.
/// Range: 1020-1023 (4 special values)
pub const SPECIAL_RANGE: Range<u32> = Range {
    start: 1020,
    end: 1024,
};

/// An interrupt identifier (INTID) for the GIC.
///
/// Represents a unique interrupt ID that can be used with the GIC hardware.
/// The GIC supports different types of interrupts based on the ID range:
///
/// - SGI (0-15): Software Generated Interrupts for inter-processor communication
/// - PPI (16-31): Private Peripheral Interrupts specific to each CPU core
/// - SPI (32-1019): Shared Peripheral Interrupts that can be routed to any CPU
/// - Special (1020-1023): Reserved interrupt IDs for special purposes
///
/// # Examples
///
/// ```
/// use arm_gic_driver::IntId;
///
/// // Create different types of interrupt IDs
/// let sgi = IntId::sgi(1); // SGI #1
/// let ppi = IntId::ppi(2); // PPI #2 (actual ID will be 18)
/// let spi = IntId::spi(42); // SPI #42 (actual ID will be 74)
///
/// // Check interrupt type
/// assert!(sgi.is_sgi());
/// assert!(ppi.is_private());
/// assert!(!spi.is_private());
/// ```
#[derive(Copy, Clone, Eq, Ord, PartialOrd, PartialEq)]
pub struct IntId(u32);

impl IntId {
    /// Create a new `IntId` from a raw interrupt ID.
    ///
    /// # Arguments
    ///
    /// * `id` - The raw interrupt ID value
    ///
    /// # Safety
    ///
    /// The caller must ensure that `id` represents a valid interrupt ID
    /// according to the GIC specification. Invalid IDs may cause undefined
    /// behavior when used with GIC operations.
    ///
    /// # Examples
    ///
    /// ```
    /// use arm_gic_driver::IntId;
    ///
    /// // Create from a known valid interrupt ID
    /// let intid = unsafe { IntId::raw(32) }; // SPI #0
    /// ```
    pub const unsafe fn raw(id: u32) -> Self {
        Self(id)
    }

    /// Create an interrupt ID for a Software Generated Interrupt.
    ///
    /// SGIs are used for inter-processor communication and are always
    /// private to the target CPU core.
    ///
    /// # Arguments
    ///
    /// * `sgi` - SGI number (0-15)
    ///
    /// # Panics
    ///
    /// Panics if `sgi` is greater than or equal to 16.
    ///
    /// # Examples
    ///
    /// ```
    /// use arm_gic_driver::IntId;
    ///
    /// let sgi1 = IntId::sgi(1);
    /// assert_eq!(sgi1.to_u32(), 1);
    /// assert!(sgi1.is_sgi());
    /// ```
    pub const fn sgi(sgi: u32) -> Self {
        assert!(sgi < SGI_RANGE.end);
        Self(sgi)
    }

    /// Create an interrupt ID for a Private Peripheral Interrupt.
    ///
    /// PPIs are peripheral interrupts that are private to each CPU core.
    /// The actual interrupt ID will be `ppi + 16`.
    ///
    /// # Arguments
    ///
    /// * `ppi` - PPI number (0-15, gets mapped to interrupt IDs 16-31)
    ///
    /// # Panics
    ///
    /// Panics if `ppi` is greater than or equal to 16.
    ///
    /// # Examples
    ///
    /// ```
    /// use arm_gic_driver::IntId;
    ///
    /// let ppi2 = IntId::ppi(2);
    /// assert_eq!(ppi2.to_u32(), 18); // 16 + 2
    /// assert!(ppi2.is_private());
    /// ```
    pub const fn ppi(ppi: u32) -> Self {
        assert!(ppi < PPI_RANGE.end - PPI_RANGE.start);
        Self(PPI_RANGE.start + ppi)
    }

    /// Create an interrupt ID for a Shared Peripheral Interrupt.
    ///
    /// SPIs are peripheral interrupts that can be routed to any CPU core.
    /// The actual interrupt ID will be `spi + 32`.
    ///
    /// # Arguments
    ///
    /// * `spi` - SPI number (0-987, gets mapped to interrupt IDs 32-1019)
    ///
    /// # Panics
    ///
    /// Panics if `spi` would result in an interrupt ID >= 1020.
    ///
    /// # Examples
    ///
    /// ```
    /// use arm_gic_driver::IntId;
    ///
    /// let spi42 = IntId::spi(42);
    /// assert_eq!(spi42.to_u32(), 74); // 32 + 42
    /// assert!(!spi42.is_private());
    /// ```
    pub const fn spi(spi: u32) -> Self {
        assert!(spi < SPECIAL_RANGE.start);
        Self(SPI_RANGE.start + spi)
    }

    /// Check if this interrupt ID is for a Software Generated Interrupt.
    ///
    /// # Returns
    ///
    /// `true` if this is an SGI (ID 0-15), `false` otherwise.
    ///
    /// # Examples
    ///
    /// ```
    /// use arm_gic_driver::IntId;
    ///
    /// assert!(IntId::sgi(5).is_sgi());
    /// assert!(!IntId::ppi(5).is_sgi());
    /// ```
    pub fn is_sgi(&self) -> bool {
        SGI_RANGE.contains(&self.0)
    }

    /// Check if this interrupt ID is private to a CPU core.
    ///
    /// Private interrupts include both SGIs (0-15) and PPIs (16-31).
    /// These interrupts cannot be routed between different CPU cores.
    ///
    /// # Returns
    ///
    /// `true` if this is a private interrupt (SGI or PPI), `false` for SPIs.
    ///
    /// # Examples
    ///
    /// ```
    /// use arm_gic_driver::IntId;
    ///
    /// assert!(IntId::sgi(1).is_private()); // SGI
    /// assert!(IntId::ppi(5).is_private()); // PPI
    /// assert!(!IntId::spi(42).is_private()); // SPI
    /// ```
    pub fn is_private(&self) -> bool {
        self.0 < SPI_RANGE.start
    }

    /// Get the raw interrupt ID as a u32 value.
    ///
    /// # Returns
    ///
    /// The interrupt ID as used by the GIC hardware.
    ///
    /// # Examples
    ///
    /// ```
    /// use arm_gic_driver::IntId;
    ///
    /// let spi = IntId::spi(10);
    /// assert_eq!(spi.to_u32(), 42); // 32 + 10
    /// ```
    pub const fn to_u32(self) -> u32 {
        self.0
    }

    /// Check if this interrupt ID is in the special range.
    ///
    /// Special interrupt IDs (1020-1023) are reserved for specific purposes
    /// and are not used for regular interrupt handling.
    ///
    /// # Returns
    ///
    /// `true` if this is a special interrupt ID, `false` otherwise.
    ///
    /// # Examples
    ///
    /// ```
    /// use arm_gic_driver::IntId;
    ///
    /// let special = unsafe { IntId::raw(1023) };
    /// assert!(special.is_special());
    ///
    /// let normal = IntId::spi(10);
    /// assert!(!normal.is_special());
    /// ```
    pub fn is_special(&self) -> bool {
        SPECIAL_RANGE.contains(&self.0)
    }
}

impl Debug for IntId {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match self.0 {
            0..16 => write!(f, "SGI {}", self.0 - SGI_RANGE.start),
            16..32 => write!(f, "PPI {}", self.0 - PPI_RANGE.start),
            32..1020 => write!(f, "SPI {}", self.0 - SPI_RANGE.start),
            1020..1024 => write!(f, "Special IntId{}", self.0),
            _ => write!(f, "Invalid IntId{}", self.0),
        }
    }
}

impl From<IntId> for u32 {
    fn from(intid: IntId) -> Self {
        intid.0
    }
}
