use crate::{core::compile_passes::Gate, utils::unique_id::UniqueId};
use core_utils::circuit::{Input, Plaintext};
use std::hash::Hash;

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub(super) struct ArcisGate {
    gate: Gate,
    /// Some identical gates need to be kept and not deduplicated.
    /// For instance, two `RandomShare` produce two different random items instead of the same one.
    /// This `id` makes them non-identical and allow us to perform CSE.
    id: Option<UniqueId>,
}

impl ArcisGate {
    pub fn new(gate: Gate) -> Self {
        // Is having the gate twice different to having it once ?
        let is_duplicate_different_from_mono = match &gate {
            Gate::Input { input_type } => match input_type {
                Input::SecretPlaintext { .. } => true,
                Input::Share { .. } => true,
                Input::RandomShare { .. } => true,
                Input::Scalar(i) => matches!(i, Plaintext::Input(_)),
                Input::ScalarBatch(i) => matches!(i, Plaintext::Input(_)),
                Input::BaseField(i) => matches!(i, Plaintext::Input(_)),
                Input::BaseFieldBatch(i) => matches!(i, Plaintext::Input(_)),
                Input::Mersenne107(i) => matches!(i, Plaintext::Input(_)),
                Input::Mersenne107Batch(i) => matches!(i, Plaintext::Input(_)),
                Input::Bit(i) => matches!(i, Plaintext::Input(_)),
                Input::BitBatch(i) => matches!(i, Plaintext::Input(_)),
                Input::Point(i) => matches!(i, Plaintext::Input(_)),
                Input::PointBatch(i) => matches!(i, Plaintext::Input(_)),
            },
            Gate::DaBit { .. } => true,
            _ => false,
        };
        let id = if is_duplicate_different_from_mono {
            Some(UniqueId::new())
        } else {
            None
        };
        ArcisGate { gate, id }
    }

    pub fn get(&self) -> &Gate {
        &self.gate
    }
}
