/*
 * asklyphe-frontend routes/user_settings.rs
 * - http routes for the settings page
 *
 * Copyright (C) 2025 Real Microsoft, LLC
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

use std::sync::Arc;
use std::sync::atomic::Ordering;
use askama::Template;
use askama_axum::IntoResponse;
use asklyphe_common::nats::authservice::{AuthError, AuthRequest, AuthResponse, AuthServiceQuery, AuthServiceRequest, AuthServiceResponse, LogoutRequest, LogoutResponse};
use asklyphe_common::nats::authservice::profile::{ThemeChangeRequest, ThemeChangeResponse, UserInfoRequest, UserInfoResponse};
use asklyphe_common::nats::comms;
use asklyphe_common::nats::comms::{ServiceError, ServiceResponse};
use async_nats::jetstream;
use axum::{Extension, Form};
use axum::response::Redirect;
use axum_extra::extract::CookieJar;
use serde::Deserialize;
use tokio::sync::Mutex;
use tracing::error;
use crate::{BUILT_ON, GIT_COMMIT, Opts, ALPHA, VERSION, WEBSITE_COUNT, YEAR};
use crate::routes::{authenticate_user, UserInfo};

pub struct Theme<'a> {
    pub value: &'a str,
    pub name: &'a str,
}

pub static THEMES: &[Theme] = &[
    Theme {
        value: "default",
        name: "default theme",
    },
    Theme {
        value: "dark",
        name: "dark theme",
    },
    Theme {
        value: "oled",
        name: "lights out",
    },
    Theme {
        value: "classic",
        name: "classic",
    },
    Theme {
        value: "freaky",
        name: "freaky",
    },
    Theme {
        value: "water",
        name: "water",
    },
    Theme {
        value: "gloss",
        name: "gloss",
    },
];

#[derive(Template)]
#[template(path = "user_settings.html")]
pub struct SettingsTemplate {
    themes: &'static [Theme<'static>],

    error: Option<String>,

    info: UserInfo,
    search_query: String,
    version: String,
    git_commit: String,
    built_on: String,
    year: String,
    alpha: bool,
    count: u64,
    theme: String,
}

pub async fn user_settings(
    jar: CookieJar,
    Extension(nats): Extension<Arc<jetstream::Context>>,
    Extension(opts): Extension<Opts>,
) -> impl IntoResponse {
    if let Some(token) = jar.get("token") {
        let token = token.value().to_string();
        let info = match authenticate_user(nats.clone(), token).await {
            Ok(i) => i,
            Err(e) => {
                return (jar.remove("token"), crate::routes::index::frontpage_error(e.as_str(), opts.auth_url.clone())).into_response();
            }
        };
        let theme = info.theme.clone();
        SettingsTemplate {
            themes: THEMES,
            error: None,
            info,
            search_query: "".to_string(),
            version: VERSION.to_string(),
            git_commit: GIT_COMMIT.to_string(),
            built_on: BUILT_ON.to_string(),
            year: YEAR.to_string(),
            alpha: ALPHA,
            count: WEBSITE_COUNT.load(Ordering::Relaxed),
            theme,
        }.into_response()
    } else {
        Redirect::temporary("/").into_response()
    }
}

#[derive(Deserialize, Debug)]
pub struct ThemeChangeForm {
    pub theme: Option<String>,
}

pub async fn theme_change_post(
    jar: CookieJar,
    Extension(nats): Extension<Arc<jetstream::Context>>,
    Extension(opts): Extension<Opts>,
    Form(input): Form<ThemeChangeForm>,
) -> impl IntoResponse {
    fn settings_error(info: UserInfo, theme: String, error: String) -> impl IntoResponse {
        SettingsTemplate {
            themes: THEMES,
            error: Some(error),
            info,
            search_query: "".to_string(),
            version: VERSION.to_string(),
            git_commit: GIT_COMMIT.to_string(),
            built_on: BUILT_ON.to_string(),
            year: YEAR.to_string(),
            alpha: ALPHA,
            count: WEBSITE_COUNT.load(Ordering::Relaxed),
            theme,
        }.into_response()
    }

    if let Some(token) = jar.get("token") {
        let token = token.value().to_string();
        let info = match authenticate_user(nats.clone(), token.clone()).await {
            Ok(i) => i,
            Err(e) => {
                return (jar.remove("token"), crate::routes::index::frontpage_error(e.as_str(), opts.auth_url.clone())).into_response();
            }
        };

        let theme = info.theme.clone();
        
        if !THEMES.iter().map(|v| v.value.to_string()).collect::<Vec<String>>().contains(&input.theme.clone().unwrap_or("default".to_string())) {
            return settings_error(info, theme, "invalid input, please try again!".to_string()).into_response();
        }

        let response = comms::query_service(comms::Query::AuthService(AuthServiceQuery {
            request: AuthServiceRequest::ThemeChangeRequest(ThemeChangeRequest {
                token,
                theme: input.theme.unwrap_or("default".to_string()),
            }),
            replyto: "".to_string(),
        }), &nats, false).await;
        if let Err(e) = response {
            error!("nats error: {:?}", e);
            settings_error(info, theme, "internal server error occurred! if the error persists, contact a developer!".to_string()).into_response()
        } else {
            let response = response.unwrap();
            match response {
                ServiceResponse::AuthService(r) => {
                    match r {
                        AuthServiceResponse::ThemeChangeResponse(r) => {
                            match r {
                                ThemeChangeResponse::Success => {
                                    Redirect::to("/user_settings").into_response()
                                }
                                ThemeChangeResponse::Logout => {
                                    (jar.remove("token"), crate::routes::index::frontpage_error("your session token was invalid, please try logging in again", opts.auth_url.clone())).into_response()
                                }
                                ThemeChangeResponse::InternalServerError => {
                                    settings_error(info, theme, "internal server error occurred! if the error persists, contact a developer!".to_string()).into_response()
                                }
                            }
                        }
                        x => {
                            error!("ERROR! RECV WRONG AUTHSERVICE RESPONSE WHEN ASKING FOR THEME CHANGE! INVESTIGATE ASAP! {x}");
                            settings_error(info, theme, "internal server error occurred! if the error persists, contact a developer!".to_string()).into_response()
                        }
                    }
                }
                x => {
                    error!("ERROR! RECV WRONG SERVICE RESPONSE WHEN ASKING AUTHSERVICE! INVESTIGATE ASAP!");
                    settings_error(info, theme, "internal server error occurred! if the error persists, contact a developer!".to_string()).into_response()
                }
            }
        }
    } else {
        Redirect::to("/").into_response()
    }
}