use std::collections::BTreeMap;

use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleFile {
    pub vars: CuddleVars,
    pub deployment: Option<CuddleDeployment>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleVars {
    pub service: String,
    pub registry: String,

    pub clusters: CuddleClusters,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleDeployment {
    pub registry: String,
    pub env: CuddleDeploymentEnv,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleDeploymentEnv(pub BTreeMap<String, CuddleDeploymentCluster>);

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleDeploymentCluster {
    pub clusters: Vec<String>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleClusters(pub BTreeMap<String, CuddleCluster>);

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct CuddleCluster {
    pub namespace: String,
}

impl CuddleFile {
    pub async fn from_cuddle_file() -> eyre::Result<Self> {
        let cuddle_file_content = tokio::fs::read_to_string("cuddle.yaml").await?;

        Self::parse_cuddle_file(&cuddle_file_content)
    }

    pub fn parse_cuddle_file(content: &str) -> eyre::Result<Self> {
        let cuddle_file: CuddleFile = serde_yaml::from_str(content)?;

        Ok(cuddle_file)
    }
}

#[cfg(test)]
mod test {
    use std::collections::BTreeMap;

    use crate::cuddle_file::{
        CuddleCluster, CuddleClusters, CuddleDeploymentCluster, CuddleDeploymentEnv, CuddleVars,
    };

    use super::CuddleFile;

    #[test]
    fn parse_file() {
        let cuddle_file = r#"
base: "git@git.front.kjuulh.io:kjuulh/cuddle-base.git"

vars:
  service: "infrastructure-example"
  registry: kasperhermansen

  clusters:
    clank_prod:
      replicas: "3"
      namespace: clank_prod

deployment:
  registry: git@git.front.kjuulh.io:kjuulh/clank-clusters
  env:
    prod:
      clusters:
        - clank_prod

scripts:
  render:
    type: shell
    args:
      cluster:
        name: cluster
        type: flag
      image_tag:
        name: image_tag
        type: flag"#;

        let res = CuddleFile::parse_cuddle_file(cuddle_file).expect("to parse file");

        let mut clusters = BTreeMap::new();
        clusters.insert(
            "clank_prod".into(),
            CuddleCluster {
                namespace: "clank_prod".into(),
            },
        );

        let mut deployment = BTreeMap::new();
        deployment.insert(
            "prod".into(),
            CuddleDeploymentCluster {
                clusters: vec!["clank_prod".into()],
            },
        );

        let expected = CuddleFile {
            vars: CuddleVars {
                service: "infrastructure-example".into(),
                registry: "kasperhermansen".into(),
                clusters: CuddleClusters(clusters),
            },
            deployment: Some(crate::cuddle_file::CuddleDeployment {
                registry: "git@git.front.kjuulh.io:kjuulh/clank-cluster".into(),
                env: CuddleDeploymentEnv(deployment),
            }),
        };

        assert_eq!(expected, res)
    }
}
