//! Server lib module to host re-usable server operations.

use super::db::Database;
use crate::models;
use crate::models::HoldPosition;
use crate::models::HoldRole;
use crate::server::config::Config;
use crate::server::db;
use redb::ReadableTable;
use std::collections::BTreeMap;

#[tracing::instrument(skip_all)]
pub(crate) async fn import_mini_moonboard_problems(config: &Config, db: Database, wall_uid: models::WallUid) -> Result<(), Error> {
    use moonboard_parser::mini_moonboard;

    let mut problems = Vec::new();

    let file_name = "problems Mini MoonBoard 2020 40.json";
    let file_path = config.moonboard_problems.join(file_name);

    tracing::info!("Parsing mini moonboard problems from {file_path}");

    let mini_moonboard = mini_moonboard::parse(file_path.as_std_path()).await?;
    for mini_mb_problem in mini_moonboard.problems {
        let mut pattern = BTreeMap::<HoldPosition, HoldRole>::new();
        for mv in mini_mb_problem.moves {
            let row = mv.description.row();
            let col = mv.description.column();
            let hold_position = HoldPosition { row, col };

            let role = match (mv.is_start, mv.is_end) {
                (true, true) => unreachable!(),
                (true, false) => HoldRole::Start,
                (false, true) => HoldRole::End,
                (false, false) => HoldRole::Normal,
            };
            pattern.insert(hold_position, role);
        }

        let method = match mini_mb_problem.method {
            mini_moonboard::Method::FeetFollowHands => models::Method::FeetFollowHands,
            mini_moonboard::Method::Footless => models::Method::Footless,
            mini_moonboard::Method::FootlessPlusKickboard => models::Method::FootlessPlusKickboard,
        };

        let pattern = models::Pattern { pattern }.canonicalize();
        let problem = models::Problem { pattern, method };
        problems.push(problem);
    }

    db.write(|txn| {
        let mut walls_table = txn.open_table(db::current::TABLE_WALLS)?;

        let mut wall = walls_table.get(wall_uid)?.unwrap().value();
        wall.problems.extend(problems);
        walls_table.insert(wall_uid, wall)?;

        Ok(())
    })
    .await?;

    Ok(())
}

#[derive(Debug, derive_more::Error, derive_more::Display, derive_more::From)]
pub enum Error {
    Parser(moonboard_parser::Error),
    Tokio(tokio::task::JoinError),
    DbOperation(crate::server::db::DatabaseOperationError),
}
