//! Customer account area. Currently just the shipping/contact profile, whose
//! fields prefill the checkout form. Gated to authenticated non-admin users:
//! anonymous visitors are bounced to `/login`. Admins have their own area and
//! are sent to the dashboard.
//!
//! The account *type* (personal vs company) is fixed at registration and lives
//! on the user — it is shown here read-only and can never be changed. The
//! profile only edits the type-specific details (company identity + address).

use axum_extra::extract::cookie::CookieJar;
use loco_rs::prelude::*;
use serde::Deserialize;
use serde_json::json;

use crate::{
    controllers::i18n::current_lang,
    models::{
        customer_profiles::{self, ProfileFields},
        users,
    },
    shared::guard,
};

#[derive(Debug, Deserialize)]
struct ProfileForm {
    company_name: Option<String>,
    company_id: Option<String>,
    tax_id: Option<String>,
    vat_id: Option<String>,
    phone_prefix: Option<String>,
    phone: Option<String>,
    address: Option<String>,
    city: Option<String>,
    zip: Option<String>,
    country: Option<String>,
}

fn trimmed(value: Option<&str>) -> Option<String> {
    value.map(str::trim).filter(|v| !v.is_empty()).map(String::from)
}

/// Build the persisted fields from the submitted form. Company identifiers are
/// only kept for company accounts (a personal account can never carry them).
fn fields_from_form(form: &ProfileForm, is_company: bool) -> ProfileFields {
    let company = |v: Option<&str>| if is_company { trimmed(v) } else { None };
    ProfileFields {
        company_name: company(form.company_name.as_deref()),
        company_id: company(form.company_id.as_deref()),
        tax_id: company(form.tax_id.as_deref()),
        vat_id: company(form.vat_id.as_deref()),
        phone_prefix: trimmed(form.phone_prefix.as_deref()),
        phone: trimmed(form.phone.as_deref()),
        address: trimmed(form.address.as_deref()),
        city: trimmed(form.city.as_deref()),
        zip: trimmed(form.zip.as_deref()),
        country: trimmed(form.country.as_deref()),
    }
}

/// The profile fields held by a saved profile, for re-prefilling the form.
fn fields_of(profile: Option<&customer_profiles::Model>) -> ProfileFields {
    match profile {
        Some(p) => ProfileFields {
            company_name: p.company_name.clone(),
            company_id: p.company_id.clone(),
            tax_id: p.tax_id.clone(),
            vat_id: p.vat_id.clone(),
            phone_prefix: p.phone_prefix.clone(),
            phone: p.phone.clone(),
            address: p.address.clone(),
            city: p.city.clone(),
            zip: p.zip.clone(),
            country: p.country.clone(),
        },
        None => ProfileFields::default(),
    }
}

/// A company account must carry its invoicing identity (company name + IČO +
/// DIČ; IČ DPH stays optional). Personal accounts have no such requirement.
fn company_fields_missing(fields: &ProfileFields) -> bool {
    fields.company_name.is_none() || fields.company_id.is_none() || fields.tax_id.is_none()
}

/// Render the profile form for `user`, prefilled from `fields`. `saved` shows
/// the success banner; `error` shows the company-required validation message.
fn profile_view(
    v: &TeraView,
    jar: &CookieJar,
    user: &users::Model,
    fields: &ProfileFields,
    saved: bool,
    error: bool,
) -> Result<Response> {
    format::view(
        v,
        "account/profile.html",
        json!({
            "logged_in_admin": false,
            "logged_in_customer": true,
            "saved": saved,
            "error": error,
            "name": user.name,
            "email": user.email,
            "account_type": user.account_type,
            "company_name": fields.company_name,
            "company_id": fields.company_id,
            "tax_id": fields.tax_id,
            "vat_id": fields.vat_id,
            "phone_prefix": fields.phone_prefix,
            "phone": fields.phone,
            "address": fields.address,
            "city": fields.city,
            "zip": fields.zip,
            "country": fields.country,
            "lang": current_lang(jar),
        }),
    )
}

#[debug_handler]
async fn profile_page(
    jar: CookieJar,
    ViewEngine(v): ViewEngine<TeraView>,
    State(ctx): State<AppContext>,
) -> Result<Response> {
    let Some(user) = guard::current_user(&ctx, &jar).await else {
        return format::redirect("/login");
    };
    if guard::is_admin(&ctx, &user) {
        return format::redirect("/admin/dashboard");
    }
    let profile = customer_profiles::Model::find_for_user(&ctx.db, user.id).await?;
    profile_view(&v, &jar, &user, &fields_of(profile.as_ref()), false, false)
}

#[debug_handler]
async fn save_profile(
    jar: CookieJar,
    ViewEngine(v): ViewEngine<TeraView>,
    State(ctx): State<AppContext>,
    Form(form): Form<ProfileForm>,
) -> Result<Response> {
    let Some(user) = guard::current_user(&ctx, &jar).await else {
        return format::redirect("/login");
    };
    if guard::is_admin(&ctx, &user) {
        return format::redirect("/admin/dashboard");
    }
    let fields = fields_from_form(&form, user.is_company());
    // A company account's profile is rejected (and re-shown with the entered
    // values) until it carries its required identifiers.
    if user.is_company() && company_fields_missing(&fields) {
        return profile_view(&v, &jar, &user, &fields, false, true);
    }
    customer_profiles::Model::upsert(&ctx.db, user.id, fields.clone()).await?;
    profile_view(&v, &jar, &user, &fields, true, false)
}

pub fn routes() -> Routes {
    Routes::new()
        .add("/account/profile", get(profile_page))
        .add("/account/profile", post(save_profile))
}
