//! JSON shaping for storefront and catalog-admin templates.

use serde_json::{json, Value};

use crate::models::_entities::{categories, products};
use crate::shared::money::format_price;

/// Card/list shape for a product: model fields plus a formatted price, its
/// optional primary image filename and category name.
pub fn product_card(
    product: &products::Model,
    image: Option<String>,
    category_name: Option<String>,
) -> Value {
    json!({
        "id": product.id,
        "name": product.name,
        "slug": product.slug,
        "description": product.description,
        "price": format_price(product.price_cents),
        "currency": product.currency,
        "sku": product.sku,
        "stock": product.stock,
        "published": product.published,
        "image": image,
        "category_name": category_name,
    })
}

/// Shape used to pre-fill the admin product form (exposes `category_id` rather
/// than a resolved name, and the current primary image).
pub fn product_form(product: &products::Model, image: Option<String>) -> Value {
    json!({
        "id": product.id,
        "name": product.name,
        "slug": product.slug,
        "description": product.description,
        "price": format_price(product.price_cents),
        "currency": product.currency,
        "sku": product.sku,
        "stock": product.stock,
        "published": product.published,
        "category_id": product.category_id,
        "image": image,
    })
}

/// Two-level grouping for the storefront sidebar menu: each top-level category
/// as `{ name, slug, children: [{ name, slug }] }`, with its direct
/// subcategories nested under `children` (empty when the category has none).
/// Siblings are ordered by position then name on both levels.
pub fn sidebar_groups(categories: &[categories::Model]) -> Vec<Value> {
    let mut top: Vec<&categories::Model> = categories
        .iter()
        .filter(|c| c.parent_id.is_none())
        .collect();
    top.sort_by(|a, b| a.position.cmp(&b.position).then_with(|| a.name.cmp(&b.name)));

    top.into_iter()
        .map(|category| {
            let children: Vec<Value> = crate::models::categories::children_of(categories, category.id)
                .into_iter()
                .map(|child| json!({ "name": child.name, "slug": child.slug }))
                .collect();
            json!({ "name": category.name, "slug": category.slug, "children": children })
        })
        .collect()
}
