// License: see LICENSE file at root directory of `master` branch

//! # Database

pub mod notifications;
pub mod users;

use std::{
    fs::OpenOptions,
    io::{Error, ErrorKind},
    path::Path,
    time::{UNIX_EPOCH, SystemTime},
};

use bailamos::Result;
use dia_args::paths::permissions::{self, Permissions};
use rusqlite::Connection;

/// # ID column
pub const ID: &str = "id";

const DB_FILE_NAME: &str = "db.sqlite";
const DB_FILE_PERMISSIONS: Permissions = 0o600;
const SETUP_SQL: &str = include_str!("db/setup.sql");

/// # Tries to connect to an existing database file; if not existed, sets up new one
pub fn connect_or_setup<P>(work_dir: P) -> Result<Connection> where P: AsRef<Path> {
    let db_file = work_dir.as_ref().canonicalize()?.join(DB_FILE_NAME);
    match db_file.exists() {
        true => {
            if db_file.is_dir() {
                return Err(Error::new(ErrorKind::InvalidInput, format!("Could not set up database on a directory: {:?}", db_file)));
            }
            permissions::r#match(&db_file, DB_FILE_PERMISSIONS)?;
        },
        false => {
            let mut options = OpenOptions::new();
            options.write(true).create(true);
            #[cfg(unix)] {
                use std::os::unix::fs::OpenOptionsExt;
                options.mode(DB_FILE_PERMISSIONS);
            }
            options.open(&db_file)?;
        },
    };

    let run_setup = db_file.exists() == false || db_file.metadata()?.len() == 0;

    let result = move || -> rusqlite::Result<_> {
        let result = Connection::open(&db_file)?;

        if run_setup {
            result.execute_batch(SETUP_SQL)?;
        }

        Ok(result)
    };
    result().map_err(|e| Error::new(ErrorKind::Other, e))
}

/// # Gets system time as Unix seconds
pub fn system_time() -> Result<i64> {
    SystemTime::now().duration_since(UNIX_EPOCH)
        .map(|d| d.as_secs() as i64)
        .map_err(|e| Error::new(ErrorKind::Other, format!("Failed getting system time: {:?}", e)))
}

#[test]
fn test_setup() {
    let conn = Connection::open_in_memory().unwrap();
    conn.execute_batch(SETUP_SQL).unwrap();
}
