extern crate tar;

use bollard::container::{Config, CreateContainerOptions, StartContainerOptions};
use bollard::exec::{CreateExecOptions, StartExecResults};
use bollard::Docker;
use bytes::{BufMut, BytesMut};
use futures_util::stream::StreamExt;
use futures_util::TryStreamExt;
use passwd::PasswdEntry;
use rand::Rng;
use std::collections::HashMap;
use std::io::Read;
use thiserror::Error;

#[derive(Debug, Error)]
pub enum DockerContainerGuardError {
    #[error("Docker API error: {0}")]
    DockerError(#[from] bollard::errors::Error),

    #[error("File not found: {0}")]
    FileNotFound(String),

    #[error("Failed to extract file: {0}")]
    FileExtractionFailed(#[from] std::io::Error),

    #[error("Too many files in tarball")]
    TooManyFilesInTarball,

    #[error("Failed to parse password entry: {0}")]
    FailedToParsePasswdEntry(#[from] passwd::PasswdEntryError),

    #[error("User not found: {0}")]
    UserNotFound(String),
}

#[derive(Debug)]
pub struct DockerContainerGuard {
    pub id: String,
    pub image: String,
    docker: Docker,
}

impl DockerContainerGuard {
    // Spawns a new container using Bollard.
    //
    // The container is automatically cleaned up when the guard goes out of scope.
    pub async fn spawn(image_name: &str) -> Result<Self, DockerContainerGuardError> {
        let docker = Docker::connect_with_local_defaults()?;

        let container_name: String = rand::thread_rng()
            .sample_iter(&rand::distributions::Alphanumeric)
            .take(10)
            .map(char::from)
            .collect();

        docker
            .create_image(
                Some(bollard::image::CreateImageOptions {
                    from_image: image_name,
                    ..Default::default()
                }),
                None,
                None,
            )
            .try_collect::<Vec<_>>()
            .await?;

        let container = docker
            .create_container(
                Some(CreateContainerOptions {
                    name: container_name,
                    ..Default::default()
                }),
                Config {
                    image: Some(image_name),
                    cmd: Some(vec!["sh"]),
                    tty: Some(true),
                    ..Default::default()
                },
            )
            .await?;

        docker
            .start_container(&container.id, None::<StartContainerOptions<String>>)
            .await?;

        Ok(Self {
            id: container.id,
            image: image_name.to_string(),
            docker,
        })
    }

    /// Executes a command inside the container using Bollard.
    ///
    /// Returns the output as a String.
    pub async fn exec(&self, cmd: Vec<&str>) -> Result<String, bollard::errors::Error> {
        let exec_instance = self
            .docker
            .create_exec(
                &self.id,
                CreateExecOptions {
                    attach_stdout: Some(true),
                    attach_stderr: Some(true),
                    cmd: Some(cmd.iter().map(|s| s.to_string()).collect()),
                    ..Default::default()
                },
            )
            .await?;
        let start_exec_result = self.docker.start_exec(&exec_instance.id, None).await?;

        if let StartExecResults::Attached {
            output: out_stream, ..
        } = start_exec_result
        {
            let output = out_stream
                .filter_map(|chunk| async {
                    match chunk {
                        Ok(bollard::container::LogOutput::StdOut { message })
                        | Ok(bollard::container::LogOutput::StdErr { message }) => {
                            Some(String::from_utf8_lossy(&message).to_string())
                        }
                        _ => None,
                    }
                })
                .fold(String::new(), |mut acc, item| async move {
                    acc.push_str(&item);
                    acc
                })
                .await;

            return Ok(output);
        }

        Ok(String::new())
    }

    // Read a file from the container.
    pub async fn read_file(&self, path: &str) -> Result<String, DockerContainerGuardError> {
        let bytes = self
            .docker
            .download_from_container::<String>(
                &self.id,
                Some(bollard::container::DownloadFromContainerOptions { path: path.into() }),
            )
            .try_fold(BytesMut::new(), |mut bytes, b| async move {
                bytes.put(b);
                Ok(bytes)
            })
            .await?;

        if bytes.len() == 0 {
            return Err(DockerContainerGuardError::FileNotFound(path.into()));
        }

        for file in tar::Archive::new(&bytes[..]).entries()? {
            let mut s = String::new();
            file?.read_to_string(&mut s).unwrap();
            return Ok(s);
        }

        Err(DockerContainerGuardError::FileNotFound(path.into()))
    }

    // Get a HashMap of all users in the container.
    pub async fn get_users(
        &self,
    ) -> Result<HashMap<String, PasswdEntry>, DockerContainerGuardError> {
        let output = self.read_file("/etc/passwd").await?;

        return output
            .lines()
            .map(|line| {
                PasswdEntry::from_line(line)
                    .map(|entry| (entry.name.clone(), entry))
                    .map_err(DockerContainerGuardError::from)
            })
            .collect();
    }

    // Get a specific user from the container.
    pub async fn get_user(&self, name: &str) -> Result<PasswdEntry, DockerContainerGuardError> {
        let users = self.get_users().await?;
        let user = users
            .get(name)
            .ok_or_else(|| DockerContainerGuardError::UserNotFound(name.into()))?;

        Ok(user.clone())
    }
}

impl Drop for DockerContainerGuard {
    fn drop(&mut self) {
        let docker = self.docker.clone();
        let container_id = self.id.clone();

        tokio::spawn(async move {
            docker
                .remove_container(
                    &container_id,
                    Some(bollard::container::RemoveContainerOptions {
                        force: true,
                        ..Default::default()
                    }),
                )
                .await
        });
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_container_exec() -> Result<(), DockerContainerGuardError> {
        let guard = DockerContainerGuard::spawn("registry.atmosphere.dev/docker.io/library/alpine:latest").await?;

        let output = guard.exec(vec!["echo", "hello from container"]).await?;
        assert!(output.contains("hello from container"));

        Ok(())
    }

    #[tokio::test]
    async fn test_container_read_file() -> Result<(), DockerContainerGuardError> {
        let guard = DockerContainerGuard::spawn("registry.atmosphere.dev/docker.io/library/alpine:latest").await?;

        let file = guard.read_file("/usr/lib/os-release").await?;
        assert!(file.len() > 0);

        Ok(())
    }

    #[tokio::test]
    async fn test_container_get_user() -> Result<(), DockerContainerGuardError> {
        let guard = DockerContainerGuard::spawn("registry.atmosphere.dev/docker.io/library/alpine:latest").await?;

        let user = guard.get_user("root").await?;
        assert_eq!(user.name, "root");

        Ok(())
    }
}
