use std::{
    env, fs,
    path::{Path, PathBuf},
};

use rusqlite::{Connection, OpenFlags};
use serde_json::{Value, json};

const MAIL_ICON: &str = "\u{f01ee}";

fn thunderbird_profile() -> Option<PathBuf> {
    let home = PathBuf::from(env::var_os("HOME")?);
    let roots = [
        home.join(".var/app/org.mozilla.Thunderbird/.thunderbird"),
        home.join(".thunderbird"),
    ];

    roots.iter().find_map(|root| {
        let mut profiles = fs::read_dir(root)
            .ok()?
            .filter_map(Result::ok)
            .map(|entry| entry.path())
            .filter(|path| {
                path.is_dir()
                    && path
                        .file_name()
                        .and_then(|name| name.to_str())
                        .is_some_and(|name| name.ends_with(".default-esr"))
            })
            .collect::<Vec<_>>();
        profiles.sort();
        profiles.into_iter().next()
    })
}

fn open_readonly_database(path: &Path) -> rusqlite::Result<Connection> {
    Connection::open_with_flags(
        path,
        OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_NO_MUTEX,
    )
}

fn unread_from_messages(conn: &Connection) -> rusqlite::Result<i64> {
    conn.query_row(
        r#"SELECT COUNT(*)
           FROM messages
           WHERE jsonAttributes LIKE '%"read":false%'
              OR jsonAttributes LIKE '%"read": false%'"#,
        [],
        |row| row.get(0),
    )
}

fn unread_from_folders(conn: &Connection) -> rusqlite::Result<i64> {
    conn.query_row(
        "SELECT SUM(numNewMessages) FROM folderlocations WHERE numNewMessages > 0",
        [],
        |row| row.get::<_, Option<i64>>(0),
    )
    .map(Option::unwrap_or_default)
}

fn unread_count(db_path: &Path) -> i64 {
    let Ok(conn) = open_readonly_database(db_path) else {
        return 0;
    };

    unread_from_messages(&conn)
        .or_else(|_| unread_from_folders(&conn))
        .unwrap_or_default()
}

fn waybar_json(count: i64) -> Value {
    if count > 0 {
        json!({
            "text": format!("{MAIL_ICON} {count}"),
            "tooltip": format!("{count} unread emails"),
            "class": "unread",
        })
    } else {
        json!({
            "text": MAIL_ICON,
            "tooltip": "No unread emails",
        })
    }
}

fn main() {
    let Some(profile) = thunderbird_profile() else {
        println!(
            "{}",
            json!({
                "text": "",
                "tooltip": "No Thunderbird profile found",
            })
        );
        return;
    };

    let db_path = profile.join("global-messages-db.sqlite");
    if !db_path.exists() {
        println!(
            "{}",
            json!({
                "text": "",
                "tooltip": "No message database",
            })
        );
        return;
    }

    println!("{}", waybar_json(unread_count(&db_path)));
}
