use crate::types::Type;
use std::fmt::{Display, Formatter, Write};

#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
pub struct Tuple {
    pub elements: Box<Vec<Type>>,
}

impl Tuple {
    pub fn new(elements: Vec<Type>) -> Tuple {
        Tuple {
            elements: Box::new(elements),
        }
    }

    pub fn with(mut self, typ: Type) -> Tuple {
        self.elements.push(typ);
        self
    }

    pub fn fmt_indented(
        &self,
        f: &mut impl Write,
        indentation: usize,
        max_fields: usize,
    ) -> std::fmt::Result {
        write!(f, "tuple(")?;
        for (i, element) in self.elements.iter().enumerate() {
            if i > 0 {
                write!(f, ", ")?;
            }
            element.fmt_indented(f, indentation, max_fields)?;
        }
        write!(f, ")")
    }

    pub fn subfields(&self) -> usize {
        self.elements
            .iter()
            .map(|element| element.subfields())
            .sum()
    }
}

impl Display for Tuple {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        self.fmt_indented(f, 0, usize::MAX)
    }
}
