use lazy_static::lazy_static;
use serde::Serialize;
use std::path::{Path, PathBuf};
use tempfile::{tempdir, TempDir};
const SERVER_PORT: u16 = 8888;
lazy_static! {
    static ref TLS_KEY: Vec<u8> =
        std::fs::read(concat!(env!("CARGO_MANIFEST_DIR"), "/tls.key")).unwrap();
    static ref TLS_CERT: Vec<u8> =
        std::fs::read(concat!(env!("CARGO_MANIFEST_DIR"), "/tls.pem")).unwrap();
}
pub struct Obnam {
    client_config: PathBuf,
    server_config: PathBuf,
    tls_key: PathBuf,
    tls_cert: PathBuf,
    root: TempDir,
    chunks: TempDir,
}
#[derive(Debug, thiserror::Error)]
pub enum ObnamError {
        #[error(transparent)]
    TempDir(#[from] std::io::Error),
}
impl Obnam {
    pub fn new() -> Result<Self, ObnamError> {
        let configs = tempdir()?;
        let path = configs.path();
        let root = tempdir()?;
        let o = Self {
            client_config: path.join("client.yaml"),
            server_config: path.join("server.yaml"),
            tls_key: path.join("tls.key"),
            tls_cert: path.join("tls.pem"),
            root,
            chunks: tempdir()?,
        };
        o.configure()?;
        Ok(o)
    }
    pub fn root(&self) -> &Path {
        self.root.path()
    }
    fn chunks(&self) -> &Path {
        self.chunks.path()
    }
    fn server_config(&self) -> &Path {
        &self.server_config
    }
    fn tls_key(&self) -> &Path {
        &self.tls_key
    }
    fn tls_cert(&self) -> &Path {
        &self.tls_cert
    }
    fn client_config(&self) -> &Path {
        &self.client_config
    }
    fn configure(&self) -> Result<(), ObnamError> {
        std::fs::write(self.tls_key(), TLS_KEY.to_vec())?;
        std::fs::write(self.tls_cert(), TLS_KEY.to_vec())?;
        ServerConfig::new(SERVER_PORT, self.chunks(), self.tls_key(), self.tls_cert())
            .write(self.server_config())?;
        ClientConfig::new(SERVER_PORT, self.root()).write(self.client_config())?;
        Ok(())
    }
    pub fn start_server(&mut self) -> Result<(), ObnamError> {
        Ok(())
    }
    pub fn stop_server(&mut self) -> Result<(), ObnamError> {
        Ok(())
    }
    pub fn backup(&mut self) -> Result<(), ObnamError> {
        Ok(())
    }
    pub fn restore(&mut self) -> Result<(), ObnamError> {
        Ok(())
    }
}
#[derive(Debug, Serialize)]
struct ServerConfig {
    address: String,
    chunks: PathBuf,
    tls_key: PathBuf,
    tls_cert: PathBuf,
}
impl ServerConfig {
    fn new(port: u16, chunks: &Path, tls_key: &Path, tls_cert: &Path) -> Self {
        Self {
            address: format!("localhost:{}", port),
            chunks: chunks.to_path_buf(),
            tls_key: tls_key.to_path_buf(),
            tls_cert: tls_cert.to_path_buf(),
        }
    }
    fn write(&self, filename: &Path) -> Result<(), ObnamError> {
        std::fs::write(filename, serde_yaml::to_string(self).unwrap())?;
        Ok(())
    }
}
#[derive(Debug, Serialize)]
struct ClientConfig {
    server_url: String,
    verify_tls_cert: bool,
    roots: Vec<PathBuf>,
    log: Option<PathBuf>,
}
impl ClientConfig {
    fn new(port: u16, root: &Path) -> Self {
        Self {
            server_url: format!("https://localhost:{}", port),
            verify_tls_cert: false,
            roots: vec![root.to_path_buf()],
            log: None,
        }
    }
    fn write(&self, filename: &Path) -> Result<(), ObnamError> {
        std::fs::write(filename, serde_yaml::to_string(self).unwrap())?;
        Ok(())
    }
}