mod callbacks;
mod config;
mod input;
mod timers;

use crate::callbacks::register_callbacks;
use crate::config::Config;
use crate::timers::register_timers;

use anyhow::Context;
use i_slint_core::model::VecModel;
use magick_rust::magick_wand_genesis;
use slint::ModelRc;
use std::rc::Rc;
use std::sync::Once;

slint::include_modules!();

static START: Once = Once::new();

use log::{debug, error, info};
use pretty_env_logger::env_logger::Target;

#[cfg(debug_assertions)]
fn start_debug_greetd_stub() {
    use libgreetd_stub::SessionOptions;

    let opts = SessionOptions {
        username: {
            std::env::var("CKGREETER_STUB_USER")
                .unwrap_or_else(|_| "debug-user".to_string())
        },
        password: std::env::var("CKGREETER_STUB_PASSWORD")
            .unwrap_or_else(|_| "debug-password".to_string()),
        mfa: false,
    };

    debug!(target: "ckgreeter::init_greetd_stub", "Using username: {}", opts.username);
    debug!(target: "ckgreeter::init_greetd_stub", "Using password: {}", opts.password);
    debug!(target: "ckgreeter::init_greetd_stub", "Using MFA: {}", opts.mfa);

    let socket_path = std::env::var("CKGREETER_STUB_SOCKET")
        .unwrap_or_else(|_| "/tmp/greetd-stub.sock".to_string());

    debug!(target: "ckgreeter::init_greetd_stub", "Using socket path: {}", socket_path);

    let stub_socket_path = socket_path.clone();
    let _stub_task = tokio::task::spawn(async move {
        libgreetd_stub::start(&stub_socket_path, &opts).await
    });
    debug!(target: "ckgreeter::init_greetd_stub", "Stub started");

    debug!(target: "ckgreeter::init_greetd_stub", "GREETD_SOCK set to {}", socket_path);
    unsafe {std::env::set_var("GREETD_SOCK", socket_path)};
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    #[cfg(debug_assertions)]
    pretty_env_logger::formatted_timed_builder()
        .target(Target::Stdout)
        .parse_filters("ckgreeter=debug")
        .parse_filters(std::env::var("RUST_LOG").unwrap_or_else(|_| "".to_string()).as_str())
        .init();
    #[cfg(not(debug_assertions))]
    pretty_env_logger::formatted_timed_builder()
        .target(Target::Stdout)
        .parse_filters("ckgreeter=info")
        .init();

    info!(target: "ckgreeter::init", "Initializing...");
    START.call_once(|| {
        magick_wand_genesis();
    });
    info!(target: "ckgreeter::init", "ImageMagick initialized");

    #[cfg(debug_assertions)]
    {
        start_debug_greetd_stub();
        info!(target: "ckgreeter::init", "Debug greetd stub started");
    }


    const CONFIG_PATH: &str = "/etc/ckgreeter/config.toml";

    let config_path = std::env::var("CKGREETER_CONFIG").unwrap_or_else(|_| CONFIG_PATH.to_string());

    if !std::fs::exists(&config_path)? {
        error!(target: "ckgreeter::init", "Config file not found at {}", config_path);
        return Err(anyhow::anyhow!("Config file not found at {}", config_path));
    }

    info!(target: "ckgreeter::init", "Loading config from {}", config_path);
    let config_data = std::fs::read(&config_path)
        .with_context(|| format!("Failed to read config file at {}", config_path))?;
    info!(target: "ckgreeter::init", "Config loaded");
    let mut config: Config = toml::from_slice(&config_data)
        .with_context(|| format!("Failed to parse config file at {}", config_path))?;
    debug!(target: "ckgreeter::init", "Config parsed");

    let display = GreeterDisplay::new()?;
    let data = display.global::<GreeterData>();

    let (tiles, default_tile) = config.get_tiles()?;

    let cache_dir = &config.background_cache_directory;
    info!(target: "ckgreeter::init", "Using cache directory: {}", cache_dir.display());
    std::fs::create_dir_all(cache_dir)
        .with_context(|| format!("Failed to create cache directory: {}", cache_dir.display()))?;


    if tiles.len() == 0 {
        error!(target: "ckgreeter::init", "No tiles found in config");
        return Err(anyhow::anyhow!("No tiles found in config"));
    }

    debug!(target: "ckgreeter::init", "Got tiles from config");

    if let Some(default_tile) = default_tile {
        debug!(target: "ckgreeter::init", "Default tile: '{}', index: {}", tiles[default_tile].name, default_tile);
        data.set_selected_index(default_tile as i32);
    }

    let tiles = Rc::new(VecModel::from(tiles));

    info!(target: "ckgreeter::init", "Registering callbacks and timers...");
    register_callbacks(&display, &data, tiles.clone(), cache_dir.into(), &config);
    info!(target: "ckgreeter::init", "Callbacks registered");
    let _timers = register_timers(&display, &data, &config);
    info!(target: "ckgreeter::init", "Timers registered");

    match config.default_username {
        Some(username) => {
            display.set_default_username(username.into());
            data.set_has_default_username(true);
        }
        None => {
            data.set_has_default_username(false);
        }
    }

    info!(target: "ckgreeter::init", "Setting up display...");

    display.set_tiles(ModelRc::from(tiles));
    debug!(target: "ckgreeter::init", "Tiles set");


    data.set_wallpaper_cooldown(config.background_delay.max(5));
    debug!(target: "ckgreeter::init", "Wallpaper cooldown set");
    data.invoke_get_new_wallpaper();
    debug!(target: "ckgreeter::init", "Wallpaper fetch invoked");
    data.invoke_check_lock_states();
    debug!(target: "ckgreeter::init", "Lock state check invoked");

    info!(target: "ckgreeter::init", "Display setup complete");
    display.show()?;
    tokio::task::block_in_place(slint::run_event_loop)?;
    display.hide()?;

    Ok(())
}