use crate::value::{Constant, Documentation};
use std::{borrow::Cow, fmt};
use super::Field;
#[derive(Debug)]
pub struct CompositeType<'a> {
    name: Constant<Cow<'a, str>>,
    documentation: Option<Documentation<'a>>,
    fields: Vec<Field<'a>>,
}
impl<'a> CompositeType<'a> {
    pub fn new(name: impl Into<Cow<'a, str>>) -> Self {
        let name = Constant::new_no_validate(name.into());
        Self {
            name,
            documentation: None,
            fields: Vec::new(),
        }
    }
    pub fn documentation(&mut self, documentation: impl Into<Cow<'a, str>>) {
        self.documentation = Some(Documentation(documentation.into()));
    }
    pub fn push_field(&mut self, field: Field<'a>) {
        self.fields.push(field);
    }
}
impl<'a> fmt::Display for CompositeType<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if let Some(ref docs) = self.documentation {
            docs.fmt(f)?;
        }
        writeln!(f, "type {} {{", self.name)?;
        for field in self.fields.iter() {
            writeln!(f, "{field}")?;
        }
        f.write_str("}\n")?;
        Ok(())
    }
}
#[cfg(test)]
mod tests {
    use expect_test::expect;
    use crate::datamodel::*;
    #[test]
    fn kitchen_sink() {
        let mut composite_type = CompositeType::new("Address");
        composite_type.documentation("...so many tears 🎵");
        let mut field = Field::new("Street", "String");
        field.native_type("db", "VarChar", vec!["255".into()]);
        field.default(DefaultValue::text("Prenzlauer Allee 193"));
        field.map("Shield");
        composite_type.push_field(field);
        let field = Field::new("Number", "Int");
        composite_type.push_field(field);
        let mut field = Field::new("City", "String");
        field.optional();
        field.documentation("...soooooooo many tears 🎵");
        composite_type.push_field(field);
        let mut field = Field::new("Other", "String");
        field.array();
        composite_type.push_field(field);
        let mut field = Field::new("Invalid", "Float");
        field.map("1Invalid");
        composite_type.push_field(field);
        let mut field = Field::new("11111", "Float");
        field.commented_out();
        field.map("11111");
        composite_type.push_field(field);
        let expected = expect![[r#"
            /// ...so many tears 🎵
            type Address {
              Street  String   @default("Prenzlauer Allee 193") @map("Shield") @db.VarChar(255)
              Number  Int
              /// ...soooooooo many tears 🎵
              City    String?
              Other   String[]
              Invalid Float    @map("1Invalid")
              // 11111 Float @map("11111")
            }
        "#]];
        let rendered = psl::reformat(&format!("{composite_type}"), 2).unwrap();
        expected.assert_eq(&rendered);
    }
}