Documentation
// Copyright (c) 2026, Salesforce, Inc.,
// All rights reserved.
// For full license text, see the LICENSE.txt file

use pel::expression::Symbol;
use pel::runtime::value::Value as PelValue;
use pel::runtime::{Binding as PelBinding, Context, ValueHandler};
use pel::Reference;
use std::borrow::Borrow;
use std::collections::HashMap;
use std::fmt::Display;
use std::hash::Hash;

#[derive(Clone, Default, Debug)]
pub struct MapContext<K>
where
    K: Eq + Hash + Display + Borrow<str>,
{
    map: HashMap<K, PelValue>,
}

impl<K> MapContext<K>
where
    K: Eq + Hash + Display + Borrow<str>,
{
    pub fn new(map: HashMap<K, PelValue>) -> Self {
        Self { map }
    }
}

impl<K> Context for MapContext<K>
where
    K: Eq + Hash + Display + Borrow<str>,
{
    fn resolve(&self, symbol: &Symbol) -> PelBinding {
        match self.map.get(symbol.as_str()) {
            Some(val) => PelBinding::Available(val.clone()),
            None => PelBinding::Unknown,
        }
    }

    fn value_handler(&self, _reference: Reference) -> Option<&dyn ValueHandler> {
        None
    }
}

impl<K> ValueHandler for MapContext<K>
where
    K: Eq + Hash + Display + Borrow<str>,
{
    fn detach(&self) -> Option<PelValue> {
        Some(PelValue::object(
            self.map
                .iter()
                .map(|(k, v)| (k.to_string(), v.clone()))
                .collect(),
        ))
    }

    fn select_by_key(&self, key: &str) -> Option<PelValue> {
        Some(self.map.get(key).cloned().unwrap_or_else(PelValue::null))
    }
}