use std::net::Ipv4Addr;
use std::path::PathBuf;

use serde::{Serialize, Deserialize};
use sqlx::SqlitePool;

use crate::errors::*;


#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AppConfig {
    #[serde(default = "default_listen_addr")]
    pub listen_addr: Ipv4Addr,
    #[serde(default = "default_listen_port")]
    pub listen_port: u16,
    #[serde(default = "default_rehide_ms")]
    pub rehide_ms: u64,
    #[serde(default = "default_start_minimized")]
    pub start_minimized: bool,
}


impl Default for AppConfig {
    fn default() -> Self {
        AppConfig {
            listen_addr: default_listen_addr(),
            listen_port: default_listen_port(),
            rehide_ms: default_rehide_ms(),
            start_minimized: default_start_minimized(),
        }
    }
}


pub async fn load(pool: &SqlitePool) -> Result<AppConfig, SetupError> {
    let res = sqlx::query!("SELECT * from config where name = 'main'")
        .fetch_optional(pool)
        .await?;

    let row = match res {
        Some(row) => row,
        None => return Ok(AppConfig::default()),
    };

    Ok(serde_json::from_str(&row.data)?)
}


pub fn get_or_create_db_path() -> PathBuf {
    if cfg!(debug_assertions) {
        return PathBuf::from("./creddy.db");
    }

    let mut parent = std::env::var("HOME")
        .map(|h| {
            let mut p = PathBuf::from(h);
            p.push(".config");
            p
        })
        .unwrap_or(PathBuf::from("."));

    parent.push("creddy.db");
    parent
}


fn default_listen_port() -> u16 {
    if cfg!(debug_assertions) {
        12_345
    }
    else {
        19_923
    }
}

fn default_listen_addr() -> Ipv4Addr { Ipv4Addr::LOCALHOST }

fn default_rehide_ms() -> u64 { 1000 }

fn default_start_minimized() -> bool { !cfg!(debug_assertions) } // default to start-minimized in production only
