use kyushu::{
    self,
    cli::{Args, EntryPrinter},
    config::Config,
    domain::requests::{Change, Request},
    persistence,
};
use redmaple::{
    event_group::EventGroup,
    id::{IDGiver, ID},
    EventRepo, RedMaple, RedMapleProjector,
};
use thiserror::Error;
use time::format_description;
use whirlybird::journey::{Event, EventWrapper};

fn main() -> color_eyre::Result<()> {
    // setting up loggers
    color_eyre::install()?;

    // Firing up generator ID

    // getting arguments
    let cli_arguments = Args::try_from(std::env::args_os())?;

    // getting configurations from cli_arguments
    let configurations = Config::from(cli_arguments.clone());

    // forming a request
    let req = cli_arguments.to_request()?;

    // creating persistence
    let repo = persistence::FileDB::try_from(
        configurations
            .file_store
            .ok_or(MainError::FileStoreCannotBeEmpty)?,
    )?;

    // matching requests to the appropiate functions
    match req {
        Request::Change(chng) => match chng {
            Change::CreateNewMaple(mpl) => {
                let new_id = mpl.id().inner();
                let created_time = time::OffsetDateTime::now_utc();
                repo.save(RedMaple::new(
                    new_id.clone(),
                    created_time,
                    vec![EventWrapper::new(
                        ID::from(created_time.unix_timestamp() as u64),
                        created_time,
                        Event::MapleCreated(mpl),
                    )],
                ))?;
                // saving in the permaenent storage
            }
        },

        Request::Information(i) => match i {
            kyushu::domain::requests::Information::ListEntries => {
                let mut redmaples = repo.all_events()?.values().collect::<Vec<_>>();

                redmaples.sort_by(|a, b| {
                    let at = a
                        .events()
                        .first()
                        .map(EventWrapper::time)
                        .unwrap_or(&time::OffsetDateTime::UNIX_EPOCH);

                    let bt = b
                        .events()
                        .first()
                        .map(EventWrapper::time)
                        .unwrap_or(&time::OffsetDateTime::UNIX_EPOCH);

                    at.cmp(bt)
                });

                redmaples
                    .iter()
                    .map(|rm| {
                        EntryPrinter::new(
                            true,
                            true,
                            format_description::parse(
                                "[year]-[month]-[day]:[hour]-[minute]-[second]",
                            )
                            .unwrap_or_default(),
                        )
                        .projector(rm)
                    })
                    .for_each(|each| println!("{each}"));
            }
        },
    };
    Ok(())
}

#[derive(Debug, Error)]
enum MainError {
    #[error("file store must be given")]
    FileStoreCannotBeEmpty,
}

// pub struct IDGenerator(SnowflakeIdBucket);

// impl IdGenerator for IDGenerator {
//     fn generate(&self) -> ID {
//         ID::new(self.0.generate())
//     }
// }

// impl IDGenerator {
//     fn new(snowflake_id_generator: SnowflakeIdGenerator) -> IDGenerator {
//         IDGenerator(snowflake_id_generator)
//     }
// }
