use std::sync::Arc;
use axum::{
    http::{
        StatusCode,
        Uri,
        header::HeaderMap,
    },
    Json,
    routing::{get,post},
    Extension,
    extract::ConnectInfo,
    response::{IntoResponse,Response,Redirect},
    Router,
};
use serde_json::{json,Value};
use tower_cookies::Cookies;
//use log::{trace,error};
use log::error;

use crate::{
    route,
    defs::{
        AppDBs,
        ReqHandler,
        ReqHeaderMap,
        Random,
        AppConnectInfo,
        FormDefs,
    },
    users::{
        User,
//        UserData,
//       UserItem,
        OpenidUser,
    },
    handlers::{
//        add_session_cookie,
        get_auth_state,
//        is_allowed,
    },
};

pub fn forms_router_handlers() -> Router {
    async fn form_handler(
        header: HeaderMap,
        uri: Uri,
        Extension(app_dbs): Extension<Arc<AppDBs>>,
        Extension(cookies): Extension<Cookies>,
        Extension(random): Extension<Random>,
        ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
        axum::extract::Path(data): axum::extract::Path<String>,
    ) -> Response {
        let auth_state = get_auth_state(true, &cookies, &app_dbs).await;
        if auth_state.session.is_none() {
           return Redirect::temporary( &format!("/login?o={}",uri.path().to_string())).into_response();
        }
        let mut req_handler = ReqHandler::new(
            ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string()), &app_connect_info),
            &app_dbs,
            &uri,
            &auth_state,
            &random,
            "user_settings_handler"
        ); 
        let mut res_headers = HeaderMap::new();
        if req_handler.req_header.is_browser() {
            res_headers.append(axum::http::header::CONTENT_TYPE,"text/html; charset=utf-8".parse().unwrap());
        }
        let user_id = auth_state.user_id();
        if user_id.is_empty() {
            let _ = req_handler.trace_req(format!("user not id found"));
            // User not exists
            return Redirect::temporary( &format!("/")).into_response();
        }
        let user_sel = User::select("id", &user_id, true, &app_dbs.user_store).await.unwrap_or_default();
        if user_sel.name.is_empty() {
            let _ = req_handler.trace_req(format!("Edit user id '{}' not found ",&user_id));
            // User not exists
            return Redirect::temporary( &format!("/")).into_response();
        }
        let openid_sel = OpenidUser::list_selection("userid", &user_sel.id.to_string(), &app_dbs.user_store, true,false, "|").await.unwrap_or_else(|e| {
            error!("Error list selection {}: {}", &user_sel.name, e);
            Vec::new()
        });

        let form_defs = FormDefs::load_from(&format!("{}/{}.toml",&app_dbs.config.forms_path, &data), &data);

        req_handler.context.insert("openid_sel", &openid_sel);
        let openid_sel_appkeys = openid_sel.iter().map(|id| id.appkey.to_string()).collect::<Vec<String>>().join(",");
        req_handler.context.insert("openid_sel_appkeys", &openid_sel_appkeys);
        req_handler.context.insert("with_menu", "1");
        req_handler.context.insert("user", &user_sel);
        req_handler.context.insert("admin_fields", &app_dbs.config.admin_fields);
        req_handler.context.insert("totp_mode", &format!("{}",&app_dbs.config.totp_mode));
        // let user_items = User::hash_items(&user_sel.items);
        // req_handler.context.insert("usr_items", &user_items);
        req_handler.context.insert("no_edit", "true");
        req_handler.context.insert("edit_target", "main");
        req_handler.context.insert("form_defs", &form_defs);
        let result = if let Some(tpl) = app_dbs.config.tpls.get("form") {
            req_handler.render_template(&tpl,"form")
        } else {
            String::from("user settings")
        };
        let _ = req_handler.trace_req(format!("User '{}' form",&user_sel.id));
        (
            res_headers,
            result.to_owned()
        ).into_response()
    }
    async fn post_form_handler(
        header: HeaderMap,
        uri: Uri,
        Extension(app_dbs): Extension<Arc<AppDBs>>,
        Extension(cookies): Extension<Cookies>,
        Extension(random): Extension<Random>,
        ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
        axum::extract::Path(form): axum::extract::Path<String>,
        Json(form_data): Json<Value>,
        
    ) -> Response {
        dbg!(&form_data);
        let str_data=serde_json::to_string(&form_data).unwrap_or_else(|e|{
            println!("from_data error: {}",e);
            String::from("")
        });
        dbg!(&str_data);
        let auth_state = get_auth_state(true, &cookies, &app_dbs).await;
        if auth_state.session.is_none() {
           return Redirect::temporary( &format!("/login?o={}",uri.path().to_string())).into_response();
        }
        let req_handler = ReqHandler::new(
            ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string()), &app_connect_info),
            &app_dbs,
            &uri,
            &auth_state,
            &random,
            "user_settings_handler"
        ); 
        //let mut res_headers = HeaderMap::new();
        //if req_handler.req_header.is_browser() {
        //   res_headers.append(axum::http::header::CONTENT_TYPE,"text/html; charset=utf-8".parse().unwrap());
        //}
        let user_id = auth_state.user_id();
        if user_id.is_empty() {
            let _ = req_handler.trace_req(format!("user not id found"));
            // User not exists
            return Redirect::temporary( &format!("/")).into_response();
        }
        let user_sel = User::select("id", &user_id, true, &app_dbs.user_store).await.unwrap_or_default();
        if user_sel.name.is_empty() {
            let _ = req_handler.trace_req(format!("Edit user id '{}' not found ",&user_id));
            // User not exists
            return Redirect::temporary( &format!("/")).into_response();
        }
        let response_path = format!("{}/{}/{}.json",&app_dbs.config.forms_responses_path,&user_id,&form);
        let form_defs = FormDefs::load_from(&format!("{}/{}.toml",&app_dbs.config.forms_path, &form), &form); 
        let write_res = match form_defs.write_data(&response_path, &str_data, form_defs.overwrite_response) {
            Ok(_) => "done",
            Err(e) => {
                println!("Error write {}: {}",&response_path, e);
                "error"
            }
        };
        let json_result = json!(
            {
                "form": form,
                "status": write_res,
            }
        );
        let result=serde_json::to_string(&json_result).unwrap_or_default(); 
        (
            StatusCode::OK, 
            req_handler.req_header.header,
            result
        ).into_response()
        // Redirect::temporary( &format!("/")).into_response()
        /*
        //let form_defs = FormDefs::load_from(&format!("{}/{}.toml",&app_dbs.config.forms_path, &data), &data);
        //req_handler.context.insert("openid_sel", &openid_sel);
        //let openid_sel_appkeys = openid_sel.iter().map(|id| id.appkey.to_string()).collect::<Vec<String>>().join(",");
        ..req_handler.context.insert("openid_sel_appkeys", &openid_sel_appkeys);
        req_handler.context.insert("with_menu", "1");
        req_handler.context.insert("user", &user_sel);
        req_handler.context.insert("admin_fields", &app_dbs.config.admin_fields);
        req_handler.context.insert("totp_mode", &format!("{}",&app_dbs.config.totp_mode));
        // let user_items = User::hash_items(&user_sel.items);
        // req_handler.context.insert("usr_items", &user_items);
        req_handler.context.insert("no_edit", "true");
        req_handler.context.insert("edit_target", "main");
        req_handler.context.insert("form_defs", &form_defs);
        let result = if let Some(tpl) = app_dbs.config.tpls.get("form") {
            req_handler.render_template(&tpl,"form")
        } else {
            String::from("user settings")
        };
        let _ = req_handler.trace_req(format!("User '{}' form",&user_sel.id));
        (
            res_headers,
            result.to_owned()
        ).into_response()
        */
    }
    route(
    "/form/:item", get(form_handler))
    .route("/form/:item", post(post_form_handler))
}
