use std::env;

use crate::db::errors::DatabaseError;
use crate::db::model_utils::Period;
use crate::db::models::{NewSchedule, Periods};
use crate::types::EmgauwaUid;
use diesel::prelude::*;
use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness};
use dotenv::dotenv;
use log::{info, trace};

pub mod errors;
pub mod models;
pub mod schedules;
pub mod schema;
pub mod tag;

mod model_utils;

pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations");

fn get_connection() -> SqliteConnection {
	dotenv().ok();

	let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
	SqliteConnection::establish(&database_url)
		.unwrap_or_else(|_| panic!("Error connecting to {}", database_url))
}

pub fn run_migrations() {
	info!("Running migrations");
	let mut connection = get_connection();
	connection
		.run_pending_migrations(MIGRATIONS)
		.expect("Failed to run migrations.");
}

fn init_schedule(schedule: &NewSchedule) -> Result<(), DatabaseError> {
	trace!("Initializing schedule {:?}", schedule.name);
	match schedules::get_schedule_by_uid(schedule.uid.clone()) {
		Ok(_) => Ok(()),
		Err(err) => match err {
			DatabaseError::NotFound => {
				trace!("Schedule {:?} not found, inserting", schedule.name);
				let mut connection = get_connection();
				diesel::insert_into(schema::schedules::table)
					.values(schedule)
					.execute(&mut connection)
					.map(|_| ())
					.map_err(DatabaseError::InsertError)
			}
			_ => Err(err),
		},
	}
}

pub fn init(db: &str) {
	run_migrations();

	init_schedule(&NewSchedule {
		uid: &EmgauwaUid::Off,
		name: "Off",
		periods: &Periods(vec![]),
	})
	.expect("Error initializing schedule Off");

	init_schedule(&NewSchedule {
		uid: &EmgauwaUid::On,
		name: "On",
		periods: &Periods(vec![Period::new_on()]),
	})
	.expect("Error initializing schedule On");
}