/*
    This file is part of jellything (https://codeberg.org/metamuffin/jellything)
    which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
    Copyright (C) 2026 metamuffin <metamuffin.org>
*/
use crate::CONF;
use crate::logic::playersync::{PlayersyncChannels, r_playersync};
use crate::ui::account::{r_account_login, r_account_logout, r_account_register};
use crate::ui::admin::import::{r_admin_import, r_admin_import_post, r_admin_import_stream};
use crate::ui::{
    account::{
        r_account_login_post, r_account_logout_post, r_account_register_post,
        settings::{r_account_settings, r_account_settings_post},
    },
    admin::{
        log::{r_admin_log, r_admin_log_stream},
        r_admin_dashboard, r_admin_invite, r_admin_remove_invite, r_admin_update_search,
        user::{r_admin_remove_user, r_admin_user, r_admin_user_permission, r_admin_users},
    },
    assets::{r_image, r_item_poster, r_node_thumbnail},
    error::{r_api_catch, r_catch},
    home::r_home,
    items::r_items,
    node::r_node,
    player::r_player,
    r_favicon, r_index,
    search::r_search,
    stats::r_stats,
    style::{r_assets_font, r_assets_js, r_assets_js_map, r_assets_style},
};
use crate::{
    api::{r_api_account_login, r_api_root, r_nodes_modified_since, r_translations, r_version},
    compat::{
        jellyfin::{
            r_jellyfin_artists, r_jellyfin_branding_configuration, r_jellyfin_branding_css,
            r_jellyfin_displaypreferences_usersettings,
            r_jellyfin_displaypreferences_usersettings_post, r_jellyfin_items,
            r_jellyfin_items_image_primary, r_jellyfin_items_images_backdrop,
            r_jellyfin_items_intros, r_jellyfin_items_item, r_jellyfin_items_playbackinfo,
            r_jellyfin_items_similar, r_jellyfin_livetv_programs_recommended, r_jellyfin_persons,
            r_jellyfin_playback_bitratetest, r_jellyfin_quickconnect_enabled,
            r_jellyfin_sessions_capabilities_full, r_jellyfin_sessions_playing,
            r_jellyfin_sessions_playing_progress, r_jellyfin_shows_nextup, r_jellyfin_socket,
            r_jellyfin_system_endpoint, r_jellyfin_system_info, r_jellyfin_system_info_public,
            r_jellyfin_system_info_public_case, r_jellyfin_users_authenticatebyname,
            r_jellyfin_users_authenticatebyname_case, r_jellyfin_users_id, r_jellyfin_users_items,
            r_jellyfin_users_items_item, r_jellyfin_users_public, r_jellyfin_users_views,
            r_jellyfin_video_stream,
        },
        youtube::{r_youtube_channel, r_youtube_embed, r_youtube_watch},
    },
    logic::{
        stream::r_stream,
        userdata::{
            r_node_userdata, r_node_userdata_progress, r_node_userdata_rating,
            r_node_userdata_watched,
        },
    },
};
use base64::Engine;
use log::warn;
use rand::random;
use rocket::{
    Build, Config, Rocket, catchers, config::SecretKey, fairing::AdHoc, fs::FileServer,
    http::Header, routes, shield::Shield,
};

#[macro_export]
macro_rules! uri {
    ($kk:stmt) => {
        &rocket::uri!($kk).to_string()
    };
}

pub fn build_rocket() -> Rocket<Build> {
    rocket::build()
        .configure(Config {
            address: std::env::var("BIND_ADDR")
                .map(|e| e.parse().unwrap())
                .unwrap_or("127.0.0.1".parse().unwrap()),
            port: std::env::var("PORT")
                .map(|e| e.parse().unwrap())
                .unwrap_or(8000),
            secret_key: SecretKey::derive_from(
                CONF.cookie_key
                    .clone()
                    .unwrap_or_else(|| {
                        warn!("cookie_key not configured, generating a random one.");
                        base64::engine::general_purpose::STANDARD.encode([(); 32].map(|_| random()))
                    })
                    .as_bytes(),
            ),
            ip_header: Some("x-real-ip".into()),
            ..Default::default()
        })
        .manage(PlayersyncChannels::default())
        .attach(AdHoc::on_response("set server header", |_req, res| {
            res.set_header(Header::new("server", "jellything"));
            Box::pin(async {})
        }))
        // TODO this would be useful but needs to handle not only the entry-point
        // .attach(AdHoc::on_response("frame options", |req, resp| {
        //     if !req.uri().path().as_str().starts_with("/embed") {
        //         resp.set_raw_header("X-Frame-Options", "SAMEORIGIN");
        //     }
        //     Box::pin(async {})
        // }))
        .attach(Shield::new())
        .register("/", catchers![r_catch])
        .register("/api", catchers![r_api_catch])
        .mount("/assets", FileServer::from(&CONF.asset_path))
        .mount(
            "/",
            routes![
                // Frontend
                r_account_login_post,
                r_account_login,
                r_account_logout_post,
                r_account_logout,
                r_account_register_post,
                r_account_register,
                r_account_settings_post,
                r_account_settings,
                r_admin_dashboard,
                r_admin_import,
                r_admin_import_post,
                r_admin_import_stream,
                r_admin_invite,
                r_admin_log_stream,
                r_admin_log,
                r_admin_remove_invite,
                r_admin_remove_user,
                r_admin_update_search,
                r_admin_user_permission,
                r_admin_user,
                r_admin_users,
                r_items,
                r_image,
                r_assets_font,
                r_assets_js_map,
                r_assets_js,
                r_assets_style,
                r_favicon,
                r_home,
                r_index,
                r_item_poster,
                r_node,
                r_node_thumbnail,
                r_node_userdata_progress,
                r_node_userdata_rating,
                r_node_userdata_watched,
                r_node_userdata,
                r_player,
                r_playersync,
                r_search,
                r_stats,
                r_stream,
                // API
                r_api_account_login,
                r_nodes_modified_since,
                r_api_root,
                r_version,
                r_translations,
                // Compat
                r_jellyfin_artists,
                r_jellyfin_branding_configuration,
                r_jellyfin_branding_css,
                r_jellyfin_displaypreferences_usersettings_post,
                r_jellyfin_displaypreferences_usersettings,
                r_jellyfin_items_image_primary,
                r_jellyfin_items_images_backdrop,
                r_jellyfin_items_intros,
                r_jellyfin_items_item,
                r_jellyfin_items_playbackinfo,
                r_jellyfin_items_similar,
                r_jellyfin_items,
                r_jellyfin_livetv_programs_recommended,
                r_jellyfin_persons,
                r_jellyfin_playback_bitratetest,
                r_jellyfin_quickconnect_enabled,
                r_jellyfin_sessions_capabilities_full,
                r_jellyfin_sessions_playing_progress,
                r_jellyfin_sessions_playing,
                r_jellyfin_shows_nextup,
                r_jellyfin_socket,
                r_jellyfin_system_endpoint,
                r_jellyfin_system_info_public_case,
                r_jellyfin_system_info_public,
                r_jellyfin_system_info,
                r_jellyfin_users_authenticatebyname,
                r_jellyfin_users_authenticatebyname_case,
                r_jellyfin_users_id,
                r_jellyfin_users_items_item,
                r_jellyfin_users_items,
                r_jellyfin_users_public,
                r_jellyfin_users_views,
                r_jellyfin_video_stream,
                r_youtube_channel,
                r_youtube_embed,
                r_youtube_watch,
            ],
        )
}
