//! Integration tests for the `install` subcommand.
//!
//! Covers: config validation (non-unique item names, invalid paths), fresh
//! and repeated installs, `--quiet` flag, and revision pinning (tags,
//! branches, commit SHAs, non-existent revisions).
//!
//! Requires network access on first run (repos are cached in `tmp/repos/`).

mod utils;

use crate::utils::{setup, write_to_file};
use anyhow::{ensure, Result};

#[test]
fn test_cli_install_subcommand_non_unique_config_item_name() -> Result<()> {
    // -------
    // Arrange
    // -------
    let (config_path, _data_path, command_vec, _temp_dir) = setup(
        "test_cli_install_subcommand_non_unique_config_item_name",
        "install",
        true,
    )?;
    let config_content = r#"[[items]]
path = "https://github.com/tinted-theming/tinted-shell"
name = "non-unique-name"
themes-dir = "some-dir"

[[items]]
path = "https://github.com/tinted-theming/tinted-shell"
name = "non-unique-name"
themes-dir = "some-dir"
"#;
    let expected_output = "config.toml item.name should be unique values, but \"non-unique-name\" is used for more than 1 item.name. Please change this to a unique value.";
    write_to_file(&config_path, config_content)?;

    // ---
    // Act
    // ---
    let (_, stderr) = utils::run_command(&command_vec)?;

    // ------
    // Assert
    // ------
    ensure!(
        stderr.contains(expected_output),
        "stdout does not contain the expected output"
    );

    Ok(())
}

#[test]
fn test_cli_install_subcommand_invalid_config_item_path() -> Result<()> {
    // -------
    // Arrange
    // -------
    let (config_path, _data_path, command_vec, _temp_dir) = setup(
        "test_cli_install_subcommand_invalid_config_item_path",
        "install",
        true,
    )?;
    let config_content = r#"[[items]]
path = "/path/to/non-existant/directory"
name = "some-name"
themes-dir = "some-dir""#;
    let expected_output = "One of your config.toml items has an invalid `path` value. \"/path/to/non-existant/directory\" is not a valid url and is not a path to an existing local directory";
    write_to_file(&config_path, config_content)?;

    // ---
    // Act
    // ---
    let (_, stderr) = utils::run_command(&command_vec)?;

    // ------
    // Assert
    // ------
    ensure!(
        stderr.contains(expected_output),
        "stdout does not contain the expected output"
    );

    Ok(())
}

#[test]
fn test_cli_install_subcommand_without_setup() -> Result<()> {
    // -------
    // Arrange
    // -------
    let (_, _data_path, command_vec, _temp_dir) = setup(
        "test_cli_install_subcommand_without_setup",
        "install",
        false,
    )?;
    let expected_output = "tinted-shell installed";

    // ---
    // Act
    // ---
    let (stdout, _) = utils::run_command(&command_vec)?;

    // ------
    // Assert
    // ------
    ensure!(
        stdout.contains(expected_output),
        "Expected stdout to contain: {expected_output}\nGot: {stdout}"
    );

    Ok(())
}

#[test]
fn test_cli_install_subcommand_with_setup() -> Result<()> {
    // -------
    // Arrange
    // -------
    let (_, _data_path, command_vec, _temp_dir) =
        setup("test_cli_install_subcommand_with_setup", "install", true)?;
    let expected_output = "tinted-shell already installed";

    // ---
    // Act
    // ---
    utils::run_command(&command_vec)?;
    let (stdout, stderr) = utils::run_command(&command_vec)?;

    // ------
    // Assert
    // ------

    ensure!(
        stdout.contains(expected_output),
        "Expected stdout to contain: {expected_output}\nGot: {stdout}"
    );
    ensure!(stderr.is_empty(), "Expected empty stderr, got: {stderr}");

    Ok(())
}

#[test]
fn test_cli_install_subcommand_with_setup_quiet_flag() -> Result<()> {
    // -------
    // Arrange
    // -------
    let (_, _data_path, command_vec, _temp_dir) = setup(
        "test_cli_install_subcommand_with_setup_quiet_flag",
        "install --quiet",
        true,
    )?;

    // ---
    // Act
    // ---
    utils::run_command(&command_vec)?;
    let (stdout, stderr) = utils::run_command(&command_vec)?;

    // ------
    // Assert
    // ------

    ensure!(stdout.is_empty(), "Expected empty stdout, got: {stdout}");
    ensure!(stderr.is_empty(), "Expected empty stderr, got: {stderr}");

    Ok(())
}

#[test]
fn test_cli_install_subcommand_with_tag_revision() -> Result<()> {
    utils::test_install_with_revision(
        "test_cli_install_subcommand_with_tag_revision",
        "https://github.com/tinted-theming/tinted-vim",
        "tinted-vim",
        "colors",
        "0e4f0d222b9013cc7e537ac6cd29bf83ba19094a",
        "0e4f0d222b9013cc7e537ac6cd29bf83ba19094a",
    )
}

#[test]
fn test_cli_install_subcommand_with_branch_revision() -> Result<()> {
    utils::test_install_with_revision(
        "test_cli_install_subcommand_with_branch_revision",
        "https://github.com/tinted-theming/tinted-jqp",
        "tinted-jqp",
        "themes",
        "tinty-test-01",
        "43b36ed5eadad59a5027e442330d2485b8607b34",
    )
}

#[test]
fn test_cli_install_subcommand_with_commit_sha1_revision() -> Result<()> {
    // This SHA1 is only reachable through the tinted-test-01 branch, but is not the tip of that
    // branch.
    utils::test_install_with_revision(
        "test_cli_install_subcommand_with_commit_sha1_revision",
        "https://github.com/tinted-theming/tinted-jqp",
        "tinted-jqp",
        "themes",
        "f998d17414a7218904bb5b4fdada5daa2b2d9d5e",
        "f998d17414a7218904bb5b4fdada5daa2b2d9d5e",
    )
}

#[test]
fn test_cli_install_subcommand_with_non_existent_revision() -> Result<()> {
    // -------
    // Arrange
    // -------
    let (config_path, data_path, command_vec, _temp_dir) = setup(
        "test_cli_install_subcommand_with_non_existent_revision",
        "install",
        false,
    )?;
    let commit_sha = "invalid-revision";
    let config_content = format!(
        r#"[[items]]
path = "https://github.com/tinted-theming/tinted-jqp"
name = "tinted-jqp"
themes-dir = "themes"
revision = "{commit_sha}"
"#
    );
    write_to_file(&config_path, &config_content)?;

    let repo_path = data_path.join("repos/tinted-jqp");

    // ---
    // Act
    // ---
    let (_, stderr) = utils::run_command(&command_vec)?;

    // ------
    // Assert
    // ------
    let path_exists = repo_path.exists();
    ensure!(
        stderr.contains(format!("cannot resolve {commit_sha}").as_str()),
        "Expected revision not found",
    );

    ensure!(
        !path_exists,
        format!("Expected repo path {} to not exist", repo_path.display())
    );

    Ok(())
}
