mod errors;
mod dns;
mod routes;
mod resources;
mod database;
mod validation;
mod macros;
mod template;
mod proto;

use std::sync::Arc;

use axum::Router;
use axum::routing;
use tower_http::services::ServeDir;

use database::sqlite::SqliteDB;
use database::BoxedDb;
use dns::dns_driver::DnsDriverConfig;
use dns::dns_driver::TsigConfig;
use dns::{ZoneDriver, RecordDriver};
use template::TemplateEngine;


#[derive(Clone)]
pub struct AppState {
    zone: Arc<dyn ZoneDriver>,
    records: Arc<dyn RecordDriver>,
    db: BoxedDb,
    template_engine: TemplateEngine
}

#[tokio::main]
async fn main() {
    let template_engine = TemplateEngine::new(std::path::Path::new("./templates"));

    let dns_driver = dns::dns_driver::DnsDriver::from_config(DnsDriverConfig {
        address: "127.0.0.1:5353".parse().unwrap(),
        tsig: Some(TsigConfig {
            key_name: "dev".parse().unwrap(),
            secret: domain::utils::base64::decode::<Vec<u8>>("mbmz4J3Efm1BUjqe12M1RHsOnPjYhKQe+2iKO4tL+a4=").unwrap(),
            algorithm: domain::tsig::Algorithm::Sha256,
        })
    });

    let dns_driver = Arc::new(dns_driver);

    let app_state = AppState {
        zone: dns_driver.clone(),
        records: dns_driver.clone(),
        db: Arc::new(SqliteDB::new("db.sqlite".into()).await),
        template_engine
    };

    let app = Router::new()
        /* ----- API ----- */
        .route("/api/admin/zones", routing::post(routes::api::zones::create_zone))
        .route("/api/zones/{zone_name}/records", routing::get(routes::api::zones::get_zone_records))
        .route("/api/zones/{zone_name}/records", routing::post(routes::api::zones::create_zone_records))
        /* ----- UI ----- */
        .route("/zones/{zone_name}/records", routing::get(routes::ui::zones::get_records_page))
        .route("/zones/{zone_name}/records/new", routing::get(routes::ui::zones::get_new_record_page))
        .nest_service("/assets", ServeDir::new("assets"))
        .with_state(app_state);

    let listener = tokio::net::TcpListener::bind("127.0.0.1:8000").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}



/*
use crate::cli::{NomiloCli, NomiloCommand};

#[database("sqlite")]
pub struct DbConn(diesel::SqliteConnection);


pub fn get_db_conn(figment: &Figment) -> diesel::SqliteConnection {
    let url = match figment.focus("databases.sqlite").extract_inner::<String>("url") {
        Ok(url) => url,
        Err(e) => {
            eprintln!("Error loading configuration: {}", e);
            exit(1);
        }
    };

    match diesel::SqliteConnection::establish(&url) {
        Ok(c) => c,
        Err(e) => {
            eprintln!("Error connecting to database at \"{}\": {}", url, e);
            exit(1);
        }
    }
}


fn main() {
    let figment = Figment::from(rocket::Config::default())
        .merge(Toml::file(Env::var_or("NOMILO_CONFIG", "nomilo.toml")).nested())
        .merge(Env::prefixed("NOMILO_").ignore(&["PROFILE"]).global())
        .select(Profile::from_env_or("NOMILO_PROFILE", "release"));

    let app_config = match figment.extract::<config::Config>() {
        Ok(c) => c,
        Err(e) => {
            eprintln!("Error loading configuration: {}",  e);
            exit(1);
        }
    };

    let nomilo = NomiloCli::parse();
    nomilo.run(figment, app_config);
}
*/