use std::collections::HashMap;
use std::sync::Arc;

use anyhow::Context;
use nutype::nutype;

mod media;

#[nutype(
    sanitize(trim, lowercase),
    validate(not_empty, regex = "^[a-z_\\-0-9]+$"),
    derive(Debug, Eq, Hash, PartialEq, Deserialize)
)]
pub struct DiskName(String);

#[derive(Debug, Default, serde::Deserialize)]
pub struct Config {
    #[serde(default)]
    pub disks: HashMap<DiskName, FileSystemConfig>,
}

impl Config {
    pub async fn build(self) -> anyhow::Result<Client> {
        let mut disks = HashMap::with_capacity(self.disks.len());
        for (name, config) in self.disks {
            let name = name.into_inner();
            let value = config
                .build()
                .with_context(|| format!("unable to build disk {name:?}"))?;
            disks.insert(name, value);
        }
        Ok(Client(Arc::new(InnerClient { disks })))
    }
}

#[derive(Clone, Debug)]
pub struct Client(Arc<InnerClient>);

#[derive(Debug)]
struct InnerClient {
    disks: HashMap<String, FileSystemClient>,
}

#[derive(Debug, serde::Deserialize)]
#[serde(tag = "type")]
pub enum FileSystemConfig {
    #[serde(rename = "pcloud")]
    PCloud(entertainarr_adapter_filesystem_pcloud::Config),
}

impl FileSystemConfig {
    fn build(self) -> anyhow::Result<FileSystemClient> {
        match self {
            Self::PCloud(inner) => inner.build().map(FileSystemClient::PCloud),
        }
    }
}

#[derive(Debug)]
pub enum FileSystemClient {
    PCloud(entertainarr_adapter_filesystem_pcloud::PcloudClient),
}
