#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

mod badge;
mod git;
mod telemetry;

use badge::set_sync_badge;
use git::{
    SearchCancellationState, add_remote, add_worktree, amend_commit, apply_file_patch,
    cancel_code_search, cancel_file_history, checkout_branch, cherry_pick_abort,
    cherry_pick_commit, cherry_pick_continue, clone_repository, commit, commit_ai_generate,
    commit_ai_load, commit_ai_local_models, commit_ai_review, commit_ai_split, commit_ai_status,
    compare_commits, compare_file_to_head, compare_file_to_parent, create_branch, create_tag,
    cred_delete, cred_load, cred_save, delete_branch, delete_remote_branch, delete_tag,
    diff_file_against_working_tree, fetch, get_file_blame, get_file_patch, get_remote_url,
    get_status, init_repository, last_commit_message, list_branches, list_commits,
    list_file_history, list_interactive_rebase_commits, list_reflog, list_remotes,
    list_repository_files, list_stashes, list_tags, list_worktrees, lock_worktree, merge_abort,
    merge_branch, merge_continue, move_worktree, open_repo_in_explorer, open_repository,
    open_repository_bundle, open_repository_file, prune_worktrees, pull, push, push_tag,
    read_conflict, rebase_abort, rebase_branch, rebase_continue, remove_remote, remove_worktree,
    rename_branch, repair_worktree, resolve_conflict, resolve_conflict_side,
    restore_file_from_commit, restore_files, restore_reflog_entry, restore_to_commit,
    revert_commit, run_sequence_editor_if_requested, search_code_introductions,
    set_branch_upstream, stage_files, start_interactive_rebase, stash_apply, stash_drop, stash_pop,
    stash_push, undo_last_commit, unlock_worktree, unstage_files, update_remote,
};
use tauri::Manager;
use telemetry::{emit_frontend_log, emit_frontend_span, set_telemetry_enabled};

struct ConsoleLogger;

impl log::Log for ConsoleLogger {
    fn enabled(&self, metadata: &log::Metadata<'_>) -> bool {
        metadata.level() <= log::Level::Info
    }

    fn log(&self, record: &log::Record<'_>) {
        if self.enabled(record.metadata()) {
            eprintln!(
                "[{}] [{}] {}",
                record.level(),
                record.target(),
                record.args()
            );
        }
    }

    fn flush(&self) {}
}

static CONSOLE_LOGGER: ConsoleLogger = ConsoleLogger;

fn init_console_logging() {
    if log::set_logger(&CONSOLE_LOGGER).is_ok() {
        log::set_max_level(log::LevelFilter::Info);
        log::info!(target: "gitty", "Rust console logging initialized");
    }
}

#[tauri::command]
fn close_splashscreen(app: tauri::AppHandle) -> Result<(), String> {
    if let Some(window) = app.get_webview_window("splashscreen") {
        let _ = window.hide();
        window
            .destroy()
            .map_err(|error| format!("failed to destroy splashscreen: {error}"))?;
    }

    if let Some(window) = app.get_webview_window("main") {
        let _ = window.maximize();
        window
            .show()
            .map_err(|error| format!("failed to show main window: {error}"))?;
        let _ = window.set_focus();
    }

    Ok(())
}

#[tokio::main]
async fn main() {
    init_console_logging();
    telemetry::init();
    if let Some(result) = run_sequence_editor_if_requested() {
        if let Err(error) = result {
            eprintln!("{error}");
            std::process::exit(1);
        }
        return;
    }

    let builder = tauri::Builder::default()
        .plugin(tauri_plugin_single_instance::init(|app, _, _| {
            #[cfg(desktop)]
            let _ = app
                .get_webview_window("main")
                .expect("no main window")
                .set_focus();
        }))
        .plugin(
            tauri_plugin_aptabase::Builder::new("A-SH-1344793789")
                .with_options(tauri_plugin_aptabase::InitOptions {
                    host: Some("https://aptabase.cbsk-tech.de".to_string()),
                    flush_interval: None,
                })
                .build(),
        )
        .manage(SearchCancellationState::default())
        .manage(commit_ai::CommitAiEngine::new())
        .plugin(tauri_plugin_dialog::init());

    // Linux installs are expected to come from the system package manager (see the
    // PKGBUILD), which owns updates itself — the self-updater is only wired up for
    // the platforms whose install method this app ships (NSIS/Windows, .app/macOS).
    #[cfg(not(target_os = "linux"))]
    let builder = builder.plugin(tauri_plugin_updater::Builder::new().build());

    builder
        .invoke_handler(tauri::generate_handler![
            open_repository,
            init_repository,
            clone_repository,
            open_repo_in_explorer,
            open_repository_file,
            get_status,
            list_branches,
            list_remotes,
            add_remote,
            update_remote,
            remove_remote,
            set_branch_upstream,
            delete_remote_branch,
            list_stashes,
            checkout_branch,
            create_branch,
            rename_branch,
            delete_branch,
            list_worktrees,
            add_worktree,
            remove_worktree,
            move_worktree,
            lock_worktree,
            unlock_worktree,
            prune_worktrees,
            repair_worktree,
            list_tags,
            create_tag,
            delete_tag,
            push_tag,
            cherry_pick_commit,
            cherry_pick_continue,
            cherry_pick_abort,
            stage_files,
            unstage_files,
            stash_push,
            stash_apply,
            stash_pop,
            stash_drop,
            restore_files,
            get_file_patch,
            apply_file_patch,
            commit,
            amend_commit,
            undo_last_commit,
            last_commit_message,
            commit_ai_status,
            commit_ai_load,
            commit_ai_local_models,
            commit_ai_generate,
            commit_ai_review,
            commit_ai_split,
            pull,
            push,
            fetch,
            list_commits,
            restore_to_commit,
            restore_file_from_commit,
            merge_branch,
            merge_continue,
            merge_abort,
            revert_commit,
            rebase_branch,
            rebase_continue,
            rebase_abort,
            list_interactive_rebase_commits,
            start_interactive_rebase,
            list_reflog,
            restore_reflog_entry,
            list_repository_files,
            open_repository_bundle,
            list_file_history,
            cancel_file_history,
            get_file_blame,
            compare_commits,
            compare_file_to_head,
            compare_file_to_parent,
            diff_file_against_working_tree,
            search_code_introductions,
            cancel_code_search,
            read_conflict,
            resolve_conflict,
            resolve_conflict_side,
            get_remote_url,
            cred_load,
            cred_save,
            cred_delete,
            set_sync_badge,
            close_splashscreen,
            set_telemetry_enabled,
            emit_frontend_log,
            emit_frontend_span
        ])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
