// {{{ Imports
use anyhow::{anyhow, Context};
use include_dir::{include_dir, Dir};
use r2d2::Pool;
use r2d2_sqlite::SqliteConnectionManager;
use rusqlite_migration::Migrations;
use std::sync::LazyLock;

use crate::arcaea::import_charts::{import_songlist, NOTECOUNT_DATA};
use crate::context::hash::{hash_bytes, hash_files};
use crate::context::paths::ShimmeringPaths;
use crate::context::process_jackets::process_jackets;
// }}}

pub type SqlitePool = r2d2::Pool<SqliteConnectionManager>;

pub fn connect_db(paths: &ShimmeringPaths) -> anyhow::Result<SqlitePool> {
	let db_path = paths.db_path();
	let mut conn = rusqlite::Connection::open(&db_path)
		.with_context(|| "Could not connect to sqlite database")?;
	conn.pragma_update(None, "journal_mode", "WAL")?;

	// {{{ Run migrations
	static MIGRATIONS_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/migrations");
	static MIGRATIONS: LazyLock<Migrations> = LazyLock::new(|| {
		Migrations::from_directory(&MIGRATIONS_DIR).expect("Could not load migrations")
	});

	MIGRATIONS
		.to_latest(&mut conn)
		.with_context(|| "Could not run migrations")?;
	println!("✅ Ensured db schema is up to date");
	// }}}
	// {{{ Check if we need to reprocess jackets
	let current_raw_jackets_hash = hash_files(&paths.raw_jackets_path())?;
	let current_songlist_hash = hash_files(&paths.songlist_path())?;
	let current_cc_data_hash = hash_files(&paths.cc_data_path())?;
	let current_notecount_hash = hash_bytes(NOTECOUNT_DATA);

	let (prev_raw_jackets_hash, prev_songlist_hash, prev_cc_data_hash, prev_notecount_hash) = conn
		.query_row("SELECT * FROM metadata", (), |row| {
			Ok((
				row.get_ref("raw_jackets_hash")?.as_str()?.to_owned(),
				row.get_ref("songlist_hash")?.as_str()?.to_owned(),
				row.get_ref("cc_data_hash")?.as_str()?.to_owned(),
				row.get_ref("notecount_hash")?.as_str()?.to_owned(),
			))
		})
		.with_context(|| anyhow!("No metadata row found"))?;

	let mut should_reprocess_jackets = true;

	if current_songlist_hash != prev_songlist_hash
		|| current_cc_data_hash != prev_cc_data_hash
		|| current_notecount_hash != prev_notecount_hash
	{
		println!("😞 Chart data hash mismatch. Re-importing everything");

		// {{ Import songlist & update hashes
		import_songlist(paths, &mut conn).context("Failed to import songlist file")?;

		conn.execute(
			"
        UPDATE metadata 
        SET songlist_hash=?,
            cc_data_hash=?,
            notecount_hash=?
      ",
			(
				current_songlist_hash,
				current_cc_data_hash,
				current_notecount_hash,
			),
		)?;
	// }}}
	} else if current_raw_jackets_hash != prev_raw_jackets_hash {
		println!("😞 Jacket hashes do not match. Re-running the processing pipeline");
	} else if !paths.recognition_matrix_path().exists() {
		println!("😞 Jacket recognition matrix not found.");
	} else if !paths.jackets_path().exists() {
		println!("😞 Processed jackets not found.");
	} else {
		println!("✅ Jacket hashes match. Skipping jacket processing");
		should_reprocess_jackets = false;
	}

	if should_reprocess_jackets {
		process_jackets(paths, &conn)?;
		conn.prepare("UPDATE metadata SET raw_jackets_hash=?")?
			.execute([current_raw_jackets_hash])?;
		println!("✅ Jacket processing pipeline run succesfully");
	}
	// }}}

	Pool::new(SqliteConnectionManager::file(&db_path))
		.with_context(|| "Could not open sqlite database.")
}