use super::{pk_to_string, pk_use_import, type_map, FieldDef};

pub fn gen(
    pascal: &str,
    snake: &str,
    fields: &[FieldDef],
    id: Option<&str>,
    timestamps: bool,
) -> String {
    let id_resource_type = match id {
        Some(_) => "String",
        None => "i64",
    };
    let id_from = pk_to_string(id);

    let mut struct_fields = format!("    pub id: {},\n", id_resource_type);
    let mut from_fields = format!("            id: {},\n", id_from);

    for f in fields {
        let tm = type_map(&f.field_type);
        let base_res_t = match f.field_type.as_str() {
            "datetime" | "date" => "String",
            "json" => "serde_json::Value",
            _ => tm.resource_type,
        };
        let (res_t, from_expr) = if f.optional {
            let opt_t = format!("Option<{base_res_t}>");
            let expr = match f.field_type.as_str() {
                "datetime" => format!("m.{}.map(|v| v.to_rfc3339())", f.name),
                "date" => format!("m.{}.map(|v| v.to_string())", f.name),
                _ => format!("m.{}", f.name),
            };
            (opt_t, expr)
        } else {
            let expr = match f.field_type.as_str() {
                "datetime" => format!("m.{}.to_rfc3339()", f.name),
                "date" => format!("m.{}.to_string()", f.name),
                _ => format!("m.{}", f.name),
            };
            (base_res_t.to_string(), expr)
        };
        struct_fields.push_str(&format!("    pub {}: {},\n", f.name, res_t));
        from_fields.push_str(&format!("            {}: {},\n", f.name, from_expr));
    }

    if timestamps {
        struct_fields.push_str("    pub created_at: String,\n");
        struct_fields.push_str("    pub updated_at: String,\n");
        from_fields.push_str("            created_at: m.created_at.to_rfc3339(),\n");
        from_fields.push_str("            updated_at: m.updated_at.to_rfc3339(),\n");
    }

    let mut uses = String::from("use serde::Serialize;\n");
    let pk_use = pk_use_import(id);
    if !pk_use.is_empty() {
        uses.push_str(pk_use);
    }

    let _ = snake;

    format!(
        "{uses}\n#[derive(Debug, Serialize)]\npub struct {pascal}Resource {{\n{struct_fields}}}\n\nimpl {pascal}Resource {{\n    pub fn from(m: super::super::models::{pascal}) -> Self {{\n        Self {{\n{from_fields}        }}\n    }}\n}}\n"
    )
}
