#![feature(rustc_private)]
use std::{fs, io, process::ExitCode};

use chrono::DateTime;
use clap::{Parser, Subcommand};
use cross::time::set_real_time;
use runtime::rt::time::{get_real_time, SystemTime};

const DEFAULT_RTC_PATH: &str = "/sys/device/rtc/rtc0/time";

#[derive(Debug, Parser)]
struct Args {
    #[clap(subcommand)]
    action: Option<Action>,
}

#[derive(Debug, Subcommand)]
enum Action {
    Get {
        #[clap(short, long)]
        rtc: bool,
    },
    Set {
        #[clap(short = 'r', long)]
        from_rtc: bool,
    },
}

impl Default for Action {
    fn default() -> Self {
        Self::Get { rtc: false }
    }
}

#[derive(Debug, thiserror::Error)]
enum Error {
    #[error("Could not get current time: {0:?}")]
    Io(#[from] io::Error),
    #[error("Time conversion error")]
    UtcTime,
}

fn read_rtc_time() -> Result<SystemTime, Error> {
    let rtc_timestamp: u64 = fs::read_to_string(DEFAULT_RTC_PATH)?
        .trim()
        .parse()
        .map_err(|_| Error::UtcTime)?;

    Ok(SystemTime::new(rtc_timestamp, 0))
}

fn get_date(rtc: bool) -> Result<(), Error> {
    let time = if rtc {
        read_rtc_time()?
    } else {
        get_real_time().map_err(io::Error::from)?
    };

    let now = DateTime::from_timestamp(time.seconds() as _, time.subsec_nanos() as _)
        .ok_or(Error::UtcTime)?;
    println!("{now}");

    Ok(())
}

fn set_date(from_rtc: bool) -> Result<(), Error> {
    let time = if from_rtc { read_rtc_time()? } else { todo!() };

    set_real_time(time.seconds(), 0)?;
    Ok(())
}

fn run(args: Args) -> Result<(), Error> {
    let action = args.action.unwrap_or_default();
    match action {
        Action::Get { rtc } => get_date(rtc),
        Action::Set { from_rtc } => set_date(from_rtc),
    }
}

fn main() -> ExitCode {
    let args = Args::parse();
    match run(args) {
        Ok(()) => ExitCode::SUCCESS,
        Err(error) => {
            eprintln!("Error: {error}");
            ExitCode::FAILURE
        }
    }
}
