//! Mode-specific construction of leaf [`EncryptedSteVecTerm`] values.
//!
//! [`PrefixMac`] picks a [`TermBuilder`] via its associated type, so the leaf
//! shape (`Compat` vs. `Standard`) is selected at type-level by the MAC choice
//! rather than threaded through a runtime mode flag.

use super::{
    mac_term::{MacBuild, MacTerm},
    ste_plaintext_term::OrderableTerm,
};
use crate::encryption::{
    json_indexer::{
        prefix_mac::{PrefixMac, UpdatePrefixMac},
        ste_vec::encrypted_term::{
            EncryptedSteVecTerm, EncryptedSteVecTermCompat, EncryptedSteVecTermStandard,
        },
    },
    EncryptionError, TokenizedSelector,
};

pub(crate) trait TermBuilder {
    fn mac_term<M, const N: usize>(
        macca: &mut M,
        selector: TokenizedSelector<N>,
        term: MacTerm,
    ) -> EncryptedSteVecTerm
    where
        M: PrefixMac + UpdatePrefixMac<MacTerm> + UpdatePrefixMac<TokenizedSelector<N>>;

    fn orderable_term<M>(
        term: OrderableTerm,
        macca: &mut M,
    ) -> Result<EncryptedSteVecTerm, EncryptionError>
    where
        M: PrefixMac + UpdatePrefixMac<&'static str>;
}

pub(crate) struct CompatTermBuilder;

impl TermBuilder for CompatTermBuilder {
    fn mac_term<M, const N: usize>(
        macca: &mut M,
        selector: TokenizedSelector<N>,
        term: MacTerm,
    ) -> EncryptedSteVecTerm
    where
        M: PrefixMac + UpdatePrefixMac<MacTerm> + UpdatePrefixMac<TokenizedSelector<N>>,
    {
        let mac = MacBuild::from((selector, term)).build(macca);
        EncryptedSteVecTerm::Compat(EncryptedSteVecTermCompat::Mac(mac))
    }

    fn orderable_term<M>(
        term: OrderableTerm,
        macca: &mut M,
    ) -> Result<EncryptedSteVecTerm, EncryptionError>
    where
        M: PrefixMac + UpdatePrefixMac<&'static str>,
    {
        term.build_compat(macca).map(EncryptedSteVecTerm::Compat)
    }
}

pub(crate) struct StandardTermBuilder;

impl TermBuilder for StandardTermBuilder {
    fn mac_term<M, const N: usize>(
        macca: &mut M,
        selector: TokenizedSelector<N>,
        term: MacTerm,
    ) -> EncryptedSteVecTerm
    where
        M: PrefixMac + UpdatePrefixMac<MacTerm> + UpdatePrefixMac<TokenizedSelector<N>>,
    {
        let mac = MacBuild::from((selector, term)).build(macca);
        EncryptedSteVecTerm::Standard(EncryptedSteVecTermStandard::Mac(mac))
    }

    fn orderable_term<M>(
        term: OrderableTerm,
        macca: &mut M,
    ) -> Result<EncryptedSteVecTerm, EncryptionError>
    where
        M: PrefixMac + UpdatePrefixMac<&'static str>,
    {
        term.build_standard(macca)
            .map(EncryptedSteVecTerm::Standard)
    }
}
