use super::bincode::Bincode;
use redb::TableDefinition;
use serde::Deserialize;
use serde::Serialize;
pub use v2::Hold;
pub use v2::HoldPosition;
pub use v2::HoldRole;
pub use v2::Image;
pub use v2::Method;
pub use v2::Problem;
pub use v2::ProblemId;
pub use v2::Root;
pub use v2::TABLE_ROOT;
pub use v2::TABLE_WALLS;
pub use v2::Wall;
pub use v2::WallId;

pub const TABLE_VERSION: TableDefinition<(), Bincode<Version>> = TableDefinition::new("version");
#[derive(Serialize, Deserialize, Debug)]
pub struct Version {
    pub version: u64,
}

pub mod v2 {
    use crate::server::db::bincode::Bincode;
    use redb::TableDefinition;
    use serde::Deserialize;
    use serde::Serialize;
    use std::collections::BTreeMap;
    use std::collections::BTreeSet;

    pub const TABLE_ROOT: TableDefinition<(), Bincode<Root>> = TableDefinition::new("root");
    pub const TABLE_WALLS: TableDefinition<Bincode<WallId>, Bincode<Wall>> = TableDefinition::new("walls");

    #[derive(Serialize, Deserialize, Debug)]
    pub struct Root {
        pub walls: BTreeSet<WallId>,
    }

    #[derive(Serialize, Deserialize, Debug)]
    pub struct Wall {
        pub uid: WallId,
        pub rows: u64,
        pub cols: u64,
        pub holds: BTreeMap<HoldPosition, Hold>,
    }

    #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
    pub struct WallId(pub uuid::Uuid);

    #[derive(Serialize, Deserialize, Debug)]
    pub struct Problem {
        pub uid: ProblemId,
        pub name: String,
        pub set_by: String,
        pub holds: BTreeMap<HoldPosition, HoldRole>,
        pub method: Method,
        pub date_added: chrono::NaiveDate,
    }

    #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
    pub struct ProblemId(pub uuid::Uuid);

    #[derive(Serialize, Deserialize, Debug)]
    pub enum Method {
        FeetFollowHands,
        Footless,
        FootlessPlusKickboard,
    }

    #[derive(Serialize, Deserialize, Debug)]
    pub enum HoldRole {
        Start,
        Normal,
        Zone,
        End,
    }

    #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord)]
    pub struct HoldPosition {
        pub row: u64,
        pub col: u64,
    }

    #[derive(Serialize, Deserialize, Debug)]
    pub struct Hold {
        pub position: HoldPosition,
        pub image: Option<Image>,
    }

    #[derive(Serialize, Deserialize, Debug)]
    pub struct Image {
        pub filename: String,
    }
}

pub mod v1 {
    use crate::server::db::bincode::Bincode;
    use crate::server::state::PersistentState;
    use redb::TableDefinition;

    pub type Root = PersistentState;

    pub const TABLE_ROOT: TableDefinition<(), Bincode<Root>> = TableDefinition::new("root");
}
