use super::{type_map, FieldDef};

pub fn gen(
    pascal: &str,
    snake: &str,
    fields: &[FieldDef],
    id: Option<&str>,
    soft_delete: bool,
    timestamps: bool,
) -> String {
    let pk_use = super::pk_use_import(id);
    let pk_type = super::pk_rust_type(id);

    let mut needs_chrono = timestamps || soft_delete;
    let mut needs_json = false;

    for f in fields {
        match f.field_type.as_str() {
            "datetime" | "date" => needs_chrono = true,
            "json" => needs_json = true,
            _ => {}
        }
    }

    let mut use_lines = String::new();
    use_lines.push_str(pk_use);
    use_lines.push_str("use rok_orm::Model;\n");
    use_lines.push_str("use serde::{Deserialize, Serialize};\n");
    if needs_chrono {
        use_lines.push_str("use chrono::{DateTime, Utc};\n");
    }
    if needs_json {
        use_lines.push_str("use serde_json::Value;\n");
    }

    let mut orm_attrs = Vec::new();
    let table = format!("{snake}s");
    orm_attrs.push(format!("table = \"{table}\""));
    if let Some(it) = id {
        orm_attrs.push(format!("id = \"{it}\""));
    }
    if timestamps {
        orm_attrs.push("timestamps".to_string());
    }
    if soft_delete {
        orm_attrs.push("soft_delete".to_string());
    }
    let orm_attr_line = format!("#[rok_orm({})]\n", orm_attrs.join(", "));

    let mut field_lines = format!("    pub id: {},\n", pk_type);
    for f in fields {
        let tm = type_map(&f.field_type);
        let base_t = match f.field_type.as_str() {
            "datetime" => "DateTime<Utc>",
            "json" => "Value",
            _ => tm.rust_type,
        };
        let rust_t = if f.optional {
            format!("Option<{base_t}>")
        } else {
            base_t.to_string()
        };
        field_lines.push_str(&format!("    pub {}: {},\n", f.name, rust_t));
    }
    if timestamps {
        field_lines.push_str("    pub created_at: DateTime<Utc>,\n");
        field_lines.push_str("    pub updated_at: DateTime<Utc>,\n");
    }
    if soft_delete {
        field_lines.push_str("    pub deleted_at: Option<DateTime<Utc>>,\n");
    }

    format!(
        "{use_lines}\n#[derive(Debug, Clone, Model, Serialize, Deserialize, sqlx::FromRow)]\n{orm_attr_line}pub struct {pascal} {{\n{field_lines}}}\n"
    )
}
