//! Internal OneHot hint type for proto deserialization.

use crate::{
    constraint::RemovedReason,
    parse::{as_constraint_id, as_variable_id, Parse, ParseError, RawParseError},
    v1, Constraint, ConstraintID, DecisionVariable, VariableID,
};
use std::collections::{BTreeMap, BTreeSet};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OneHot {
    pub id: ConstraintID,
    pub variables: BTreeSet<VariableID>,
}

impl Parse for v1::OneHot {
    type Output = OneHot;
    type Context = (
        BTreeMap<VariableID, DecisionVariable>,
        BTreeMap<ConstraintID, Constraint>,
        BTreeMap<ConstraintID, (Constraint, RemovedReason)>,
    );
    fn parse(
        self,
        (decision_variable, constraints, removed_constraints): &Self::Context,
    ) -> Result<Self::Output, ParseError> {
        let message = "ommx.v1.OneHot";
        let constraint_id = as_constraint_id(constraints, removed_constraints, self.constraint_id)
            .map_err(|e| e.context(message, "constraint_id"))?;
        let mut variables = BTreeSet::new();
        for v in &self.decision_variables {
            let id = as_variable_id(decision_variable, *v)
                .map_err(|e| e.context(message, "decision_variables"))?;
            if !variables.insert(id) {
                return Err(RawParseError::InvalidInstance(format!(
                    "Non-unique variable ID is found where uniqueness is required: {id:?}"
                ))
                .context(message, "decision_variables"));
            }
        }
        Ok(OneHot {
            id: constraint_id,
            variables,
        })
    }
}
