use rusqlite::Connection;
use std::sync::Mutex;
use std::path::PathBuf;
use tauri::Manager;

mod database;
mod commands;
mod os_detection;

pub struct AppState {
    pub db: Mutex<Connection>,
    pub data_dir: PathBuf,
}

fn get_data_dir() -> PathBuf {
    let exe_path = std::env::current_exe().unwrap();
    let data_dir = exe_path.parent().unwrap().join("data");
    std::fs::create_dir_all(&data_dir).ok();
    data_dir
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    env_logger::init();

    let data_dir = get_data_dir();
    let db_path = data_dir.join("timetracker.db");

    let conn = Connection::open(&db_path).expect("Failed to open database");
    database::init_db(&conn).expect("Failed to initialize database");
    commands::seed_default_templates(&data_dir);

    tauri::Builder::default()
        .plugin(tauri_plugin_window_state::Builder::new()
            .with_denylist(&["mini-timer"])
            .build())
        .plugin(tauri_plugin_shell::init())
        .plugin(tauri_plugin_dialog::init())
        .plugin(tauri_plugin_fs::init())
        .plugin(tauri_plugin_notification::init())
        .plugin(tauri_plugin_global_shortcut::Builder::new().build())
        .manage(AppState { db: Mutex::new(conn), data_dir: data_dir.clone() })
        .invoke_handler(tauri::generate_handler![
            commands::get_clients,
            commands::create_client,
            commands::update_client,
            commands::delete_client,
            commands::get_client_dependents,
            commands::get_projects,
            commands::create_project,
            commands::update_project,
            commands::delete_project,
            commands::get_project_dependents,
            commands::get_tasks,
            commands::create_task,
            commands::delete_task,
            commands::update_task,
            commands::get_time_entries,
            commands::create_time_entry,
            commands::update_time_entry,
            commands::delete_time_entry,
            commands::get_reports,
            commands::create_invoice,
            commands::get_invoices,
            commands::update_invoice,
            commands::delete_invoice,
            commands::update_invoice_template,
            commands::get_invoice_items,
            commands::create_invoice_item,
            commands::delete_invoice_items,
            commands::save_invoice_items_batch,
            commands::get_settings,
            commands::update_settings,
            commands::export_data,
            commands::clear_all_data,
            commands::get_idle_seconds,
            commands::get_visible_windows,
            commands::get_running_processes,
            commands::get_tracked_apps,
            commands::add_tracked_app,
            commands::remove_tracked_app,
            commands::get_tags,
            commands::create_tag,
            commands::update_tag,
            commands::delete_tag,
            commands::get_entry_tags,
            commands::set_entry_tags,
            commands::get_project_budget_status,
            commands::get_favorites,
            commands::create_favorite,
            commands::delete_favorite,
            commands::reorder_favorites,
            commands::get_goal_progress,
            commands::get_profitability_report,
            commands::get_timesheet_data,
            commands::import_entries,
            commands::import_json_data,
            commands::save_binary_file,
            commands::open_mini_timer,
            commands::close_mini_timer,
            commands::get_invoice_templates,
            commands::get_recurring_entries,
            commands::create_recurring_entry,
            commands::update_recurring_entry,
            commands::delete_recurring_entry,
            commands::update_recurring_last_triggered,
            commands::get_expenses,
            commands::create_expense,
            commands::update_expense,
            commands::delete_expense,
            commands::get_uninvoiced_expenses,
            commands::mark_expenses_invoiced,
            commands::get_timeline_events,
            commands::create_timeline_event,
            commands::update_timeline_event_ended,
            commands::delete_timeline_events,
            commands::clear_all_timeline_data,
            commands::get_calendar_sources,
            commands::create_calendar_source,
            commands::update_calendar_source,
            commands::delete_calendar_source,
            commands::import_ics_file,
            commands::get_calendar_events,
            commands::lock_timesheet_week,
            commands::unlock_timesheet_week,
            commands::get_timesheet_locks,
            commands::is_week_locked,
            commands::update_invoice_status,
            commands::check_overdue_invoices,
            commands::get_time_entries_paginated,
            commands::bulk_delete_entries,
            commands::bulk_update_entries_project,
            commands::bulk_update_entries_billable,
            commands::upsert_timesheet_entry,
            commands::get_entry_templates,
            commands::create_entry_template,
            commands::delete_entry_template,
            commands::update_entry_template,
            commands::get_timesheet_rows,
            commands::save_timesheet_rows,
            commands::get_previous_week_structure,
            commands::auto_backup,
            commands::search_entries,
            commands::list_backup_files,
            commands::delete_backup_file,
            commands::get_recent_descriptions,
            commands::check_entry_overlap,
            commands::get_task_actuals,
            commands::get_invoice_payments,
            commands::add_invoice_payment,
            commands::delete_invoice_payment,
            commands::get_recurring_invoices,
            commands::create_recurring_invoice,
            commands::update_recurring_invoice,
            commands::delete_recurring_invoice,
            commands::check_recurring_invoices,
        ])
        .setup(|app| {
            #[cfg(desktop)]
            {
                use tauri::tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent};
                use tauri::menu::{Menu, MenuItem};

                let quit = MenuItem::with_id(app, "quit", "Quit", true, None::<&str>)?;
                let show = MenuItem::with_id(app, "show", "Show Window", true, None::<&str>)?;
                let menu = Menu::with_items(app, &[&show, &quit])?;

                let _tray = TrayIconBuilder::new()
                    .icon(app.default_window_icon().unwrap().clone())
                    .menu(&menu)
                    .show_menu_on_left_click(false)
                    .on_menu_event(|app, event| {
                        match event.id.as_ref() {
                            "quit" => {
                                app.exit(0);
                            }
                            "show" => {
                                if let Some(window) = app.get_webview_window("main") {
                                    window.show().ok();
                                    window.set_focus().ok();
                                }
                            }
                            _ => {}
                        }
                    })
                    .on_tray_icon_event(|tray, event| {
                        if let TrayIconEvent::Click {
                            button: MouseButton::Left,
                            button_state: MouseButtonState::Up,
                            ..
                        } = event {
                            let app = tray.app_handle();
                            if let Some(window) = app.get_webview_window("main") {
                                window.show().ok();
                                window.set_focus().ok();
                            }
                        }
                    })
                    .build(app)?;
            }
            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
