// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html

use camino::Utf8Path;

use crate::{
    action::BuildAction,
    build::FilesHandle,
    input::{space_separated, BuildInput},
};

/// Rsync the provided inputs into `output_folder`, preserving directory structure,
/// eg foo/bar.js -> out/$target_folder/foo/bar.js. `strip_prefix` can be used to
/// remove a portion of the the path when copying. If the input files are from previous
/// build outputs, the prefix should begin with `$builddir/`.
pub struct RsyncFiles<'a> {
    pub inputs: BuildInput,
    pub target_folder: &'a str,
    pub strip_prefix: &'static str,
    pub extra_args: &'a str,
}

impl BuildAction for RsyncFiles<'_> {
    fn command(&self) -> &str {
        "$runner rsync $extra_args --prefix $stripped_prefix --inputs $inputs_without_prefix --output-dir $builddir/$output_folder"
    }

    fn files(&mut self, build: &mut impl FilesHandle) {
        let inputs = build.expand_inputs(&self.inputs);
        build.add_inputs_vec("", inputs.clone());
        let output_folder = Utf8Path::new(self.target_folder);
        let (prefix, inputs_without_prefix) = if self.strip_prefix.is_empty() {
            (".", inputs)
        } else {
            let stripped_inputs = inputs
                .iter()
                .map(|p| {
                    Utf8Path::new(p)
                        .strip_prefix(self.strip_prefix)
                        .unwrap_or_else(|_| {
                            panic!("expected {} to start with {}", p, self.strip_prefix)
                        })
                        .to_string()
                })
                .collect();
            (self.strip_prefix, stripped_inputs)
        };
        build.add_variable(
            "inputs_without_prefix",
            space_separated(&inputs_without_prefix),
        );
        build.add_variable("stripped_prefix", prefix);
        build.add_variable("output_folder", self.target_folder);
        if !self.extra_args.is_empty() {
            build.add_variable(
                "extra_args",
                format!("--extra-args {}", self.extra_args.replace(' ', ",")),
            );
        }

        let outputs = inputs_without_prefix
            .iter()
            .map(|p| output_folder.join(p).to_string());
        build.add_outputs("", outputs);
    }

    fn check_output_timestamps(&self) -> bool {
        true
    }
}
