use anyhow::*;
use chrono::{Timelike, Utc};
use indexmap::IndexMap;
use serde::Serialize;
use std::path::{Path, PathBuf};
use std::result::Result::Ok;

/// Generates json for tauri updater.
#[derive(clap::Parser)]
pub struct Command {
    #[clap(long = "assets", default_value = "assets")]
    assets_dir: PathBuf,
    #[clap(long = "version")]
    version: String,
    out_path: PathBuf,
}

impl crate::Command for Command {
    fn run(self) -> Result<i32> {
        create_alcom_updater_json(&self.assets_dir, &self.version, &self.out_path)?;
        Ok(0)
    }
}

#[derive(Serialize)]
struct UpdaterJson<'a> {
    version: &'a str,
    notes: String,
    pub_date: chrono::DateTime<Utc>,
    platforms: IndexMap<String, Platform>,
}

#[derive(serde::Serialize)]
struct Platform {
    signature: String,
    url: String,
    args: Vec<String>,
}

pub fn create_alcom_updater_json(assets_dir: &Path, version: &str, out_path: &Path) -> Result<()> {
    // consts
    const DOWNLOAD_URL_BASE: &str = "https://github.com/CQMHV/ALCOMD3/releases/download/v{version}";
    const WINDOWS_SETUP_FILE_NAME: &str = "alcomd3-{version}-setup.exe";
    let platform_file_name = [("windows-x86_64", WINDOWS_SETUP_FILE_NAME)]
        .into_iter()
        .collect::<IndexMap<_, _>>();

    let base_url = DOWNLOAD_URL_BASE.replace("{version}", version);

    // create platforms info
    let mut platforms = IndexMap::new();
    for (platform, file_name) in platform_file_name {
        let file_name = file_name.replace("{version}", version);

        std::fs::metadata(assets_dir.join(&file_name)).with_context(|| file_name.clone())?;

        let sig_name = format!("{file_name}.sig");
        let signature = std::fs::read_to_string(assets_dir.join(&sig_name))
            .with_context(|| sig_name.clone())?;

        let url = format!("{base_url}/{file_name}");
        platforms.insert(
            platform.to_string(),
            Platform {
                signature,
                url,
                args: vec![],
            },
        );
    }

    platforms["windows-x86_64"].args = [
        "/SP-",
        "/SILENT",
        "/NOICONS",
        "!peruser:/CURRENTUSER",
        "!machine:/ALLUSERS",
    ]
    .iter()
    .map(|x| x.to_string())
    .collect();

    let notes = format!(
        "ALCOMD3 v{version}. See https://github.com/CQMHV/ALCOMD3/releases/tag/v{version} for details."
    );

    let updater = UpdaterJson {
        version,
        notes,
        pub_date: Utc::now().with_nanosecond(0).unwrap(),
        platforms,
    };

    let json = serde_json::to_string_pretty(&updater)?;
    std::fs::write(out_path, json).context("write updater.json")?;

    Ok(())
}
