use crate::vm::value::IdentifierValue;

#[derive(Debug, Clone, PartialEq)]
pub struct FunctionSignature {
    pub required_arguments: Vec<IdentifierValue>,
    pub optional_arguments: Vec<IdentifierValue>,
    pub rest_argument: Option<IdentifierValue>,
}

impl FunctionSignature {
    pub const EMPTY: Self = Self {
        required_arguments: vec![],
        optional_arguments: vec![],
        rest_argument: None,
    };

    pub fn argument(&self, name: &str) -> Option<usize> {
        if let Some(index) = self
            .required_arguments
            .iter()
            .position(|a| a.as_ref() == name)
        {
            Some(index)
        } else if let Some(index) = self
            .optional_arguments
            .iter()
            .position(|a| a.as_ref() == name)
        {
            Some(index + self.required_arguments.len())
        } else if self
            .rest_argument
            .as_ref()
            .is_some_and(|a| a.as_ref() == name)
        {
            Some(self.required_arguments.len() + self.optional_arguments.len())
        } else {
            None
        }
    }

    pub fn min_arity(&self) -> usize {
        self.required_arguments.len()
    }

    pub fn max_arity(&self) -> usize {
        if self.rest_argument.is_none() {
            self.required_arguments.len() + self.optional_arguments.len()
        } else {
            usize::MAX
        }
    }
}
