//! Integration tests for CLI execution commands
#![allow(deprecated)]

use assert_cmd::Command;
use predicates::prelude::*;

mod common;
use common::*;

#[tokio::test]
async fn test_execution_list_authenticated() {
    let fixture = TestFixture::new().await;
    fixture.write_authenticated_config("valid_token", "refresh_token");

    // Mock execution list endpoint
    mock_execution_list(&fixture.mock_server).await;

    let mut cmd = Command::cargo_bin("attune").unwrap();
    cmd.env("XDG_CONFIG_HOME", fixture.config_dir_path())
        .env("HOME", fixture.config_dir_path())
        .arg("--api-url")
        .arg(fixture.server_url())
        .arg("execution")
        .arg("list");

    cmd.assert()
        .success()
        .stdout(predicate::str::contains("succeeded"))
        .stdout(predicate::str::contains("failed"));
}

#[tokio::test]
async fn test_execution_list_unauthenticated() {
    let fixture = TestFixture::new().await;
    fixture.write_default_config();

    // Mock unauthorized response
    mock_unauthorized(&fixture.mock_server, "/api/v1/executions").await;

    let mut cmd = Command::cargo_bin("attune").unwrap();
    cmd.env("XDG_CONFIG_HOME", fixture.config_dir_path())
        .env("HOME", fixture.config_dir_path())
        .arg("--api-url")
        .arg(fixture.server_url())
        .arg("execution")
        .arg("list");

    cmd.assert().failure();
}

#[tokio::test]
async fn test_execution_list_json_output() {
    let fixture = TestFixture::new().await;
    fixture.write_authenticated_config("valid_token", "refresh_token");

    // Mock execution list endpoint
    mock_execution_list(&fixture.mock_server).await;

    let mut cmd = Command::cargo_bin("attune").unwrap();
    cmd.env("XDG_CONFIG_HOME", fixture.config_dir_path())
        .env("HOME", fixture.config_dir_path())
        .arg("--api-url")
        .arg(fixture.server_url())
        .arg("--json")
        .arg("execution")
        .arg("list");

    cmd.assert()
        .success()
        .stdout(predicate::str::contains(r#""status": "succeeded""#))
        .stdout(predicate::str::contains(r#""status": "failed""#));
}

#[tokio::test]
async fn test_execution_list_yaml_output() {
    let fixture = TestFixture::new().await;
    fixture.write_authenticated_config("valid_token", "refresh_token");

    // Mock execution list endpoint
    mock_execution_list(&fixture.mock_server).await;

    let mut cmd = Command::cargo_bin("attune").unwrap();
    cmd.env("XDG_CONFIG_HOME", fixture.config_dir_path())
        .env("HOME", fixture.config_dir_path())
        .arg("--api-url")
        .arg(fixture.server_url())
        .arg("--yaml")
        .arg("execution")
        .arg("list");

    cmd.assert()
        .success()
        .stdout(predicate::str::contains("status: succeeded"))
        .stdout(predicate::str::contains("status: failed"));
}

#[tokio::test]
async fn test_execution_get_by_id() {
    let fixture = TestFixture::new().await;
    fixture.write_authenticated_config("valid_token", "refresh_token");

    // Mock execution get endpoint
    mock_execution_get(&fixture.mock_server, 123, "succeeded").await;

    let mut cmd = Command::cargo_bin("attune").unwrap();
    cmd.env("XDG_CONFIG_HOME", fixture.config_dir_path())
        .env("HOME", fixture.config_dir_path())
        .arg("--api-url")
        .arg(fixture.server_url())
        .arg("execution")
        .arg("show")
        .arg("123");

    cmd.assert()
        .success()
        .stdout(predicate::str::contains("succeeded"));
}

#[tokio::test]
async fn test_execution_get_not_found() {
    let fixture = TestFixture::new().await;
    fixture.write_authenticated_config("valid_token", "refresh_token");

    // Mock 404 response
    mock_not_found(&fixture.mock_server, "/api/v1/executions/999").await;

    let mut cmd = Command::cargo_bin("attune").unwrap();
    cmd.env("XDG_CONFIG_HOME", fixture.config_dir_path())
        .env("HOME", fixture.config_dir_path())
        .arg("--api-url")
        .arg(fixture.server_url())
        .arg("execution")
        .arg("show")
        .arg("999");

    cmd.assert()
        .failure()
        .stderr(predicate::str::contains("Error"));
}

#[tokio::test]
async fn test_execution_list_with_status_filter() {
    let fixture = TestFixture::new().await;
    fixture.write_authenticated_config("valid_token", "refresh_token");

    // Mock execution list with filter
    use serde_json::json;
    use wiremock::{
        matchers::{method, path, query_param},
        Mock, ResponseTemplate,
    };

    Mock::given(method("GET"))
        .and(path("/api/v1/executions"))
        .and(query_param("status", "succeeded"))
        .respond_with(ResponseTemplate::new(200).set_body_json(json!({
            "data": [
                {
                    "id": 1,
                    "action_ref": "core.echo",
                    "status": "succeeded",
                    "parent": null,
                    "enforcement": null,
                    "result": {"output": "Hello"},
                    "created": "2024-01-01T00:00:00Z",
                    "updated": "2024-01-01T00:00:00Z"
                }
            ]
        })))
        .mount(&fixture.mock_server)
        .await;

    let mut cmd = Command::cargo_bin("attune").unwrap();
    cmd.env("XDG_CONFIG_HOME", fixture.config_dir_path())
        .env("HOME", fixture.config_dir_path())
        .arg("--api-url")
        .arg(fixture.server_url())
        .arg("execution")
        .arg("list")
        .arg("--status")
        .arg("succeeded");

    cmd.assert()
        .success()
        .stdout(predicate::str::contains("succeeded"));
}

#[tokio::test]
async fn test_execution_result_raw_output() {
    let fixture = TestFixture::new().await;
    fixture.write_authenticated_config("valid_token", "refresh_token");

    // Mock execution get endpoint with result
    use serde_json::json;
    use wiremock::{
        matchers::{method, path},
        Mock, ResponseTemplate,
    };

    Mock::given(method("GET"))
        .and(path("/api/v1/executions/123"))
        .respond_with(ResponseTemplate::new(200).set_body_json(json!({
            "data": {
                "id": 123,
                "action_ref": "core.echo",
                "status": "succeeded",
                "config": {"message": "Hello"},
                "result": {"output": "Hello World", "exit_code": 0},
                "parent": null,
                "enforcement": null,
                "executor": null,
                "created": "2024-01-01T00:00:00Z",
                "updated": "2024-01-01T00:00:00Z"
            }
        })))
        .mount(&fixture.mock_server)
        .await;

    let mut cmd = Command::cargo_bin("attune").unwrap();
    cmd.env("XDG_CONFIG_HOME", fixture.config_dir_path())
        .env("HOME", fixture.config_dir_path())
        .arg("--api-url")
        .arg(fixture.server_url())
        .arg("execution")
        .arg("result")
        .arg("123");

    cmd.assert()
        .success()
        .stdout(predicate::str::contains("Hello World"))
        .stdout(predicate::str::contains("exit_code"));
}

#[tokio::test]
async fn test_execution_list_with_pack_filter() {
    let fixture = TestFixture::new().await;
    fixture.write_authenticated_config("valid_token", "refresh_token");

    // Mock execution list with pack filter
    use serde_json::json;
    use wiremock::{
        matchers::{method, path, query_param},
        Mock, ResponseTemplate,
    };

    Mock::given(method("GET"))
        .and(path("/api/v1/executions"))
        .and(query_param("pack_name", "core"))
        .respond_with(ResponseTemplate::new(200).set_body_json(json!({
            "data": [
                {
                    "id": 1,
                    "action_ref": "core.echo",
                    "status": "succeeded",
                    "parent": null,
                    "enforcement": null,
                    "result": {"output": "Test output"},
                    "created": "2024-01-01T00:00:00Z",
                    "updated": "2024-01-01T00:00:00Z"
                }
            ]
        })))
        .mount(&fixture.mock_server)
        .await;

    let mut cmd = Command::cargo_bin("attune").unwrap();
    cmd.env("XDG_CONFIG_HOME", fixture.config_dir_path())
        .env("HOME", fixture.config_dir_path())
        .arg("--api-url")
        .arg(fixture.server_url())
        .arg("execution")
        .arg("list")
        .arg("--pack")
        .arg("core");

    cmd.assert().success();
}

#[tokio::test]
async fn test_execution_list_with_action_filter() {
    let fixture = TestFixture::new().await;
    fixture.write_authenticated_config("valid_token", "refresh_token");

    // Mock execution list with action filter
    use serde_json::json;
    use wiremock::{
        matchers::{method, path, query_param},
        Mock, ResponseTemplate,
    };

    Mock::given(method("GET"))
        .and(path("/api/v1/executions"))
        .and(query_param("action_ref", "core.echo"))
        .respond_with(ResponseTemplate::new(200).set_body_json(json!({
            "data": [
                {
                    "id": 1,
                    "action_ref": "core.echo",
                    "status": "succeeded",
                    "parent": null,
                    "enforcement": null,
                    "result": {"output": "Echo test"},
                    "created": "2024-01-01T00:00:00Z",
                    "updated": "2024-01-01T00:00:00Z"
                }
            ]
        })))
        .mount(&fixture.mock_server)
        .await;

    let mut cmd = Command::cargo_bin("attune").unwrap();
    cmd.env("XDG_CONFIG_HOME", fixture.config_dir_path())
        .env("HOME", fixture.config_dir_path())
        .arg("--api-url")
        .arg(fixture.server_url())
        .arg("execution")
        .arg("list")
        .arg("--action")
        .arg("core.echo");

    cmd.assert().success();
}

#[tokio::test]
async fn test_execution_list_multiple_filters() {
    let fixture = TestFixture::new().await;
    fixture.write_authenticated_config("valid_token", "refresh_token");

    // Mock execution list with multiple filters
    use serde_json::json;
    use wiremock::{
        matchers::{method, path, query_param},
        Mock, ResponseTemplate,
    };

    Mock::given(method("GET"))
        .and(path("/api/v1/executions"))
        .and(query_param("status", "succeeded"))
        .and(query_param("pack_name", "core"))
        .respond_with(ResponseTemplate::new(200).set_body_json(json!({
            "data": [
                {
                    "id": 1,
                    "action_ref": "core.echo",
                    "status": "succeeded",
                    "parent": null,
                    "enforcement": null,
                    "result": {},
                    "created": "2024-01-01T00:00:00Z",
                    "updated": "2024-01-01T00:00:00Z"
                }
            ]
        })))
        .mount(&fixture.mock_server)
        .await;

    let mut cmd = Command::cargo_bin("attune").unwrap();
    cmd.env("XDG_CONFIG_HOME", fixture.config_dir_path())
        .env("HOME", fixture.config_dir_path())
        .arg("--api-url")
        .arg(fixture.server_url())
        .arg("execution")
        .arg("list")
        .arg("--status")
        .arg("succeeded")
        .arg("--pack")
        .arg("core");

    cmd.assert().success();
}

#[tokio::test]
async fn test_execution_get_with_profile() {
    let fixture = TestFixture::new().await;

    // Create multi-profile config
    let config = format!(
        r#"
current_profile: default
default_output_format: table
profiles:
  default:
    api_url: {}
    auth_token: valid_token
    refresh_token: refresh_token
    description: Default server
  production:
    api_url: {}
    auth_token: prod_token
    refresh_token: prod_refresh
    description: Production server
"#,
        fixture.server_url(),
        fixture.server_url()
    );
    fixture.write_config(&config);

    // Mock execution get endpoint
    mock_execution_get(&fixture.mock_server, 456, "running").await;

    let mut cmd = Command::cargo_bin("attune").unwrap();
    cmd.env("XDG_CONFIG_HOME", fixture.config_dir_path())
        .env("HOME", fixture.config_dir_path())
        .arg("--profile")
        .arg("production")
        .arg("execution")
        .arg("show")
        .arg("456");

    cmd.assert()
        .success()
        .stdout(predicate::str::contains("running"));
}

#[tokio::test]
async fn test_execution_list_empty_result() {
    let fixture = TestFixture::new().await;
    fixture.write_authenticated_config("valid_token", "refresh_token");

    // Mock empty execution list
    use serde_json::json;
    use wiremock::{
        matchers::{method, path},
        Mock, ResponseTemplate,
    };

    Mock::given(method("GET"))
        .and(path("/api/v1/executions"))
        .respond_with(ResponseTemplate::new(200).set_body_json(json!({
            "data": []
        })))
        .mount(&fixture.mock_server)
        .await;

    let mut cmd = Command::cargo_bin("attune").unwrap();
    cmd.env("XDG_CONFIG_HOME", fixture.config_dir_path())
        .env("HOME", fixture.config_dir_path())
        .arg("--api-url")
        .arg(fixture.server_url())
        .arg("execution")
        .arg("list");

    cmd.assert().success();
}

#[tokio::test]
async fn test_execution_get_invalid_id() {
    let fixture = TestFixture::new().await;
    fixture.write_authenticated_config("valid_token", "refresh_token");

    let mut cmd = Command::cargo_bin("attune").unwrap();
    cmd.env("XDG_CONFIG_HOME", fixture.config_dir_path())
        .env("HOME", fixture.config_dir_path())
        .arg("--api-url")
        .arg(fixture.server_url())
        .arg("execution")
        .arg("show")
        .arg("not_a_number");

    cmd.assert()
        .failure()
        .stderr(predicate::str::contains("invalid"));
}
