//! Admin management of the alternative display currencies.
//!
//! EUR is the base/transaction currency and is shown read-only for context. The
//! admin sets each alternative currency's exchange rate (units per 1 EUR) and
//! toggles whether buyers may switch to it. The currencies themselves are fixed
//! and seeded by `initializers::currency_seeder`.

use axum_extra::extract::cookie::CookieJar;
use loco_rs::prelude::*;
use sea_orm::{ActiveModelTrait, EntityTrait, QueryOrder, Set};
use serde::Deserialize;
use serde_json::json;

use crate::{
    controllers::i18n::current_lang,
    models::currencies,
    shared::{
        currency::{self, BASE_CODE, BASE_SYMBOL},
        guard,
    },
};

#[derive(Debug, Deserialize)]
struct CurrencyForm {
    rate: String,
    enabled: Option<String>,
}

fn is_checked(value: &Option<String>) -> bool {
    matches!(value.as_deref(), Some("on" | "true" | "1"))
}

#[debug_handler]
async fn index(
    auth: auth::JWT,
    jar: CookieJar,
    ViewEngine(v): ViewEngine<TeraView>,
    State(ctx): State<AppContext>,
) -> Result<Response> {
    guard::current_admin(auth, &ctx).await?;
    let rows = currencies::Entity::find()
        .order_by_asc(currencies::Column::Code)
        .all(&ctx.db)
        .await?;
    let currencies_json: Vec<serde_json::Value> = rows
        .iter()
        .map(|c| {
            json!({
                "id": c.id,
                "code": c.code,
                "symbol": c.symbol,
                "rate": currency::format_rate(c.rate_e4),
                "enabled": c.enabled,
            })
        })
        .collect();
    format::view(
        &v,
        "admin/currencies/index.html",
        json!({
            "base_code": BASE_CODE,
            "base_symbol": BASE_SYMBOL,
            "currencies": currencies_json,
            "lang": current_lang(&jar),
        }),
    )
}

#[debug_handler]
async fn update(
    auth: auth::JWT,
    Path(id): Path<i32>,
    State(ctx): State<AppContext>,
    Form(form): Form<CurrencyForm>,
) -> Result<Response> {
    guard::current_admin(auth, &ctx).await?;
    let row = currencies::Entity::find_by_id(id)
        .one(&ctx.db)
        .await?
        .ok_or_else(|| Error::NotFound)?;
    let mut active = row.into_active_model();
    active.rate_e4 = Set(currency::parse_rate(&form.rate)?);
    active.enabled = Set(is_checked(&form.enabled));
    active.update(&ctx.db).await?;
    // Keep the navbar/settings chrome snapshot in sync with the new rate/state.
    currency::refresh_snapshot(&ctx.db).await?;
    format::redirect("/admin/currencies")
}

pub fn routes() -> Routes {
    Routes::new()
        .add("/admin/currencies", get(index))
        .add("/admin/currencies/{id}", post(update))
}
