// Copyright © 2023 Kim Altintop <kim@eagain.io>
// SPDX-License-Identifier: GPL-2.0-only

use std::{
    collections::HashMap,
    ffi::OsString,
    fs::File,
    io::Write,
};

use chrono::{
    TimeZone as _,
    Utc,
};
use once_cell::sync::Lazy;
use tempfile::{
    tempdir,
    TempDir,
};
use test_log::test;

use super::*;

static ALICE: Lazy<Identity> = Lazy::new(|| {
    Identity {
        display_name: "Alice".into(),
        email: "alice@example.com".into(),
        last_modified: Utc.with_ymd_and_hms(2023, 10, 4, 13, 33, 53).unwrap(),
        public_key: PublicKey {
            version: 0,
            algorithm: Algorithm::Ed25519,
            expires: None,
            signature: "2gZ2P25vNVgCPim8XY6GJNJWbBm4vzqZ5g9ti9VffojUUhLybhhV3QycNhyaCa6pPogjsNj9sdgQ2rjgeSnyghz8".into(),
            key: "FYAsb1jhNwopkb38rrLxK1Ka2UFkJw6mQhXy8iD9bkBx".into()
        }
    }
});

static BOB: Lazy<Identity> = Lazy::new(|| {
    Identity {
        display_name: "Bob".into(),
        email: "bob@example.com".into(),
        last_modified: Utc.with_ymd_and_hms(2023, 10, 4, 13, 33, 38).unwrap(),
        public_key: PublicKey {
            version: 0,
            algorithm: Algorithm::Ed25519,
            expires: None,
            signature: "21GFwPQppUzXaBcfShBYwqrYxJAYgyJrfShS6fmcQ2bcJXasqaQtxYPgzZQy64Dq1rxAPmwzEYTLjEeCDDsLgfrE".into(),
            key: "D7qbdVjnf4GjH4q6uqVerFWjaypL7wQ7arCfaEcPQDqG".into()
        }
    }
});

struct ConfigDir {
    #[allow(unused)]
    tmp: TempDir,
    env: Option<OsString>,
}

impl ConfigDir {
    fn setup() -> anyhow::Result<Self> {
        let tmp = tempdir()?;
        let env = env::var_os("PIJUL_CONFIG_DIR");

        let identities = tmp.path().join("identities");
        let a = identities.join("a");
        let b = identities.join("b");

        for (mut dir, id) in [(a, &*ALICE), (b, &*BOB)] {
            fs::create_dir_all(&dir)?;
            let toml = toml::to_string(id)?;
            dir.push("identity.toml");
            File::create(dir)?.write_all(toml.as_bytes())?;
        }

        env::set_var("PIJUL_CONFIG_DIR", tmp.path());

        Ok(Self { tmp, env })
    }
}

impl Drop for ConfigDir {
    fn drop(&mut self) {
        if let Some(prev) = self.env.take() {
            env::set_var("PIJUL_CONFIG_DIR", prev)
        }
    }
}

#[test]
fn list() {
    let _cfg = ConfigDir::setup().unwrap();

    let mut ids = Identity::list().collect::<Result<Vec<_>, _>>().unwrap();
    ids.sort();
    assert_eq!(vec!["a", "b"], ids)
}

#[test]
fn load_all() {
    let _cfg = ConfigDir::setup().unwrap();

    let actual = Identity::load_all()
        .collect::<Result<HashMap<_, _>, _>>()
        .unwrap();
    let expected = HashMap::from([
        ("a".to_owned(), ALICE.clone()),
        ("b".to_owned(), BOB.clone()),
    ]);
    assert_eq!(expected, actual);
}