use axum::extract::State;
use serde::Deserialize;
use serde_json::from_str;

use crate::{
    database::{self, DbError, SelectSdkAccount},
    services::fail_json,
    SdkState,
};

use super::{json, post, Json, Router, Value};

#[derive(Deserialize)]
struct RequestData {
    pub uid: String,
    pub token: String,
}

#[derive(Deserialize)]
struct GranterTokenRequest {
    pub data: String,
    pub device: String,
}

pub fn routes() -> Router<SdkState> {
    Router::new().route(
        "/:product_name/combo/granter/login/v2/login",
        post(granter_login_verification),
    )
}

async fn granter_login_verification(
    state: State<SdkState>,
    request: Json<GranterTokenRequest>,
) -> Json<Value> {
    let Ok(data) = from_str::<RequestData>(&request.data) else {
        return fail_json(-101, "Account token error");
    };

    let Ok(uid) = data.uid.parse::<i32>() else {
        return fail_json(-101, "Account token error");
    };

    match database::select_sdk_account(&state.pg_pool, SelectSdkAccount::ByUid(uid)).await {
        Ok(account) if account.token == data.token => (),
        _ => return fail_json(-101, "Account token error"),
    }

    match database::select_combo_token_by_account(&state.pg_pool, &data.uid).await {
        Ok(token) => success_json(&data.uid, &token.token),
        Err(DbError::NotFound) => {
            let Ok(token) =
                database::insert_combo_token(&state.pg_pool, &data.uid, &request.device).await
            else {
                return fail_json(-1, "Internal server error");
            };

            success_json(&data.uid, &token.token)
        }
        Err(DbError::SqlxError(err)) => {
            tracing::error!("SQL error: {err}");
            fail_json(-1, "Internal server error")
        }
    }
}

fn success_json(uid: &str, token: &str) -> Json<Value> {
    Json(json!({
        "data": {
            "account_type": 1,
            "combo_id": uid,
            "combo_token": token,
            "data": "{\"guest\":false}",
            "heartbeat": false,
            "open_id": uid
        },
        "message": "OK",
        "retcode": 0
    }))
}
