use std::io;

use async_trait::async_trait;
use inquire::Confirm;
use log::{info, warn};
use tokio::sync::OnceCell;

use crate::{
    interpret::{InterpretError, Outcome},
    inventory::Inventory,
    maestro::Maestro,
    modules::k3d::K3DInstallationScore,
    topology::LocalhostTopology,
};

use super::{Topology, k8s::K8sClient};

struct K8sState {
    client: K8sClient,
    source: K8sSource,
    message: String,
}

enum K8sSource {
    RemoteCluster,
    LocalK3d,
    // TODO: Add variants for cloud providers like AwsEks, Gke, Aks
}

pub struct K8sAnywhereTopology {
    k8s_state: OnceCell<Option<K8sState>>,
}

impl K8sAnywhereTopology {
    async fn try_load_system_kubeconfig(&self) -> Option<K8sClient> {
        todo!("Use kube-rs default behavior to load system kubeconfig");
    }

    async fn try_load_kubeconfig(&self, path: &str) -> Option<K8sClient> {
        todo!("Use kube-rs to load kubeconfig at path {path}");
    }

    async fn try_install_k3d(&self) -> Result<K8sClient, InterpretError> {
        let maestro = Maestro::new(Inventory::autoload(), LocalhostTopology::new());
        let k3d_score = K3DInstallationScore::new();
        maestro.interpret(Box::new(k3d_score)).await?;
        todo!(
            "Create Maestro with LocalDockerTopology or something along these lines and run a K3dInstallationScore on it"
        );
    }

    async fn try_get_or_install_k8s_client(&self) -> Result<Option<K8sState>, InterpretError> {
        let k8s_anywhere_config = K8sAnywhereConfig {
            kubeconfig: std::env::var("HARMONY_KUBECONFIG")
                .ok()
                .map(|v| v.to_string()),
            use_system_kubeconfig: std::env::var("HARMONY_USE_SYSTEM_KUBECONFIG")
                .map_or_else(|_| false, |v| v.parse().ok().unwrap_or(false)),
            autoinstall: std::env::var("HARMONY_AUTOINSTALL")
                .map_or_else(|_| false, |v| v.parse().ok().unwrap_or(false)),
        };

        if k8s_anywhere_config.use_system_kubeconfig {
            match self.try_load_system_kubeconfig().await {
                Some(client) => todo!(),
                None => todo!(),
            }
        }

        if let Some(kubeconfig) = k8s_anywhere_config.kubeconfig {
            match self.try_load_kubeconfig(&kubeconfig).await {
                Some(client) => todo!(),
                None => todo!(),
            }
        }

        info!("No kubernetes configuration found");

        if !k8s_anywhere_config.autoinstall {
            let confirmation = Confirm::new( "Harmony autoinstallation is not activated, do you wish to launch autoinstallation? : ")
                .with_default(false)
                .prompt()
                .expect("Unexpected prompt error");

            if !confirmation {
                warn!(
                    "Installation cancelled, K8sAnywhere could not initialize a valid Kubernetes client"
                );
                return Ok(None);
            }
        }

        info!("Starting K8sAnywhere installation");
        match self.try_install_k3d().await {
            Ok(client) => Ok(Some(K8sState {
                client,
                source: K8sSource::LocalK3d,
                message: "Successfully installed K3D cluster and acquired client".to_string(),
            })),
            Err(_) => todo!(),
        }
    }
}

struct K8sAnywhereConfig {
    /// The path of the KUBECONFIG file that Harmony should use to interact with the Kubernetes
    /// cluster
    ///
    /// Default : None
    kubeconfig: Option<String>,

    /// Whether to use the system KUBECONFIG, either the environment variable or the file in the
    /// default or configured location
    ///
    /// Default : false
    use_system_kubeconfig: bool,

    /// Whether to install automatically a kubernetes cluster
    ///
    /// When enabled, autoinstall will setup a K3D cluster on the localhost. https://k3d.io/stable/
    ///
    /// Default: true
    autoinstall: bool,
}

#[async_trait]
impl Topology for K8sAnywhereTopology {
    fn name(&self) -> &str {
        todo!()
    }

    async fn ensure_ready(&self) -> Result<Outcome, InterpretError> {
        match self
            .k8s_state
            .get_or_try_init(|| self.try_get_or_install_k8s_client())
            .await?
        {
            Some(k8s_state) => Ok(Outcome::success(k8s_state.message.clone())),
            None => Err(InterpretError::new(
                "No K8s client could be found or installed".to_string(),
            )),
        }
    }
}
