#![allow(clippy::unwrap_used)]
// Tests can use unwrap() for simplicity
// Integration Tests for Dockerfile Purification - End-to-End Workflows
// EXTREME TDD Phase 7: INTEGRATION
//
// Test Naming Convention: test_integration_<workflow>_<scenario>
//
// Purpose: Verify complete end-to-end workflows combining multiple transformations
#![allow(non_snake_case)] // Test naming convention allows descriptive names

use assert_cmd::Command;
use std::fs;
use std::io::Write;
use tempfile::{NamedTempFile, TempDir};

// ============================================================================
// Helper Functions
// ============================================================================

/// Create a bashrs command (MANDATORY pattern per CLAUDE.md)
fn bashrs_cmd() -> Command {
    Command::cargo_bin("bashrs").expect("Failed to find bashrs binary")
}

/// Create a temporary Dockerfile with given content
fn create_temp_dockerfile(content: &str) -> NamedTempFile {
    let mut file = NamedTempFile::new().expect("Failed to create temp file");
    file.write_all(content.as_bytes())
        .expect("Failed to write to temp file");
    file
}

// ============================================================================
// Integration Test 1: Multi-Transformation Workflow
// ============================================================================

#[test]
fn test_integration_all_transformations_combined() {
    // Test that all 6 DOCKER transformations work together correctly
    let dockerfile = r#"FROM ubuntu:latest
RUN apt-get update && apt-get install -y curl wget
ADD https://example.com/file.tar.gz /tmp/
ADD local-file.txt /app/
COPY app.py /app/
"#;

    let input_file = create_temp_dockerfile(dockerfile);
    let output_dir = TempDir::new().expect("Failed to create temp dir");
    let output_file = output_dir.path().join("Dockerfile.purified");

    bashrs_cmd()
        .arg("dockerfile")
        .arg("purify")
        .arg(input_file.path())
        .arg("-o")
        .arg(&output_file)
        .assert()
        .success();

    let purified = fs::read_to_string(&output_file).expect("Failed to read purified file");

    // Verify DOCKER001: FROM latest → FROM ubuntu:22.04 (versioned)
    // NOTE: Current implementation pins version but doesn't add -slim suffix
    // This matches DOCKER002 behavior (version pinning only)
    assert!(
        purified.contains("FROM ubuntu:22.04") || purified.contains("FROM ubuntu:20.04"),
        "DOCKER001 transformation failed: {}",
        purified
    );

    // Verify DOCKER005: --no-install-recommends added
    assert!(
        purified.contains("--no-install-recommends"),
        "DOCKER005 transformation failed"
    );

    // Verify DOCKER003: Package cleanup added
    assert!(
        purified.contains("/var/lib/apt/lists"),
        "DOCKER003 transformation failed"
    );

    // Verify DOCKER006: ADD → COPY for local files
    assert!(
        purified.contains("COPY local-file.txt"),
        "DOCKER006 transformation failed (local file)"
    );

    // Verify DOCKER006: ADD preserved for URLs
    assert!(
        purified.contains("ADD https://example.com"),
        "DOCKER006 transformation failed (URL preservation)"
    );
}

// ============================================================================
// Integration Test 2: Real-World Node.js Dockerfile
// ============================================================================

#[test]
fn test_integration_nodejs_dockerfile() {
    // Realistic Node.js application Dockerfile
    let dockerfile = r#"FROM node:latest
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
"#;

    let input_file = create_temp_dockerfile(dockerfile);
    let output_dir = TempDir::new().expect("Failed to create temp dir");
    let output_file = output_dir.path().join("Dockerfile");

    bashrs_cmd()
        .arg("dockerfile")
        .arg("purify")
        .arg(input_file.path())
        .arg("-o")
        .arg(&output_file)
        .assert()
        .success();

    let purified = fs::read_to_string(&output_file).expect("Failed to read purified file");

    // Verify FROM latest is transformed
    assert!(
        !purified.contains("node:latest"),
        "Node.js Dockerfile should not have :latest tag"
    );

    // Verify structure is preserved
    assert!(purified.contains("WORKDIR /app"));
    assert!(purified.contains("EXPOSE 3000"));
    assert!(purified.contains("CMD"));
}

// ============================================================================
// Integration Test 3: Real-World Python Dockerfile
// ============================================================================

#[test]
fn test_integration_python_dockerfile() {
    // Realistic Python application Dockerfile
    let dockerfile = r#"FROM python:latest
WORKDIR /app
RUN apt-get update && apt-get install -y gcc g++ make
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]
"#;

    let input_file = create_temp_dockerfile(dockerfile);
    let output_dir = TempDir::new().expect("Failed to create temp dir");
    let output_file = output_dir.path().join("Dockerfile");

    bashrs_cmd()
        .arg("dockerfile")
        .arg("purify")
        .arg(input_file.path())
        .arg("-o")
        .arg(&output_file)
        .assert()
        .success();

    let purified = fs::read_to_string(&output_file).expect("Failed to read purified file");

    // Verify all transformations applied
    assert!(!purified.contains("python:latest"));
    assert!(purified.contains("--no-install-recommends"));
    assert!(purified.contains("/var/lib/apt/lists"));
}

// ============================================================================
// Integration Test 4: Idempotency Verification
// ============================================================================

#[test]
fn test_integration_idempotency_purify_twice() {
    // Verify that purifying twice produces identical results
    let dockerfile = r#"FROM ubuntu:latest
RUN apt-get install -y nginx
"#;

    let input_file = create_temp_dockerfile(dockerfile);
    let temp_dir = TempDir::new().expect("Failed to create temp dir");

    // First purification
    let output1 = temp_dir.path().join("Dockerfile.purified1");
    bashrs_cmd()
        .arg("dockerfile")
        .arg("purify")
        .arg(input_file.path())
        .arg("-o")
        .arg(&output1)
        .assert()
        .success();

    let purified1 = fs::read_to_string(&output1).expect("Failed to read first purified file");

    // Second purification (purify the purified file)
    let output2 = temp_dir.path().join("Dockerfile.purified2");
    bashrs_cmd()
        .arg("dockerfile")
        .arg("purify")
        .arg(&output1)
        .arg("-o")
        .arg(&output2)
        .assert()
        .success();

    let purified2 = fs::read_to_string(&output2).expect("Failed to read second purified file");

    // Verify idempotency: purify(purify(x)) == purify(x)
    assert_eq!(
        purified1, purified2,
        "Purification should be idempotent (same result when applied twice)"
    );
}

// ============================================================================
// Integration Test 5: Comments Preserved During Transformations
// ============================================================================

#[test]
fn test_integration_comments_preserved() {
    // Verify that comments are preserved during all transformations
    let dockerfile = r#"# Base image
FROM ubuntu:latest

# Update and install packages
RUN apt-get update && apt-get install -y curl

# Copy application files
COPY app.py /app/
"#;

    let input_file = create_temp_dockerfile(dockerfile);
    let output_dir = TempDir::new().expect("Failed to create temp dir");
    let output_file = output_dir.path().join("Dockerfile");

    bashrs_cmd()
        .arg("dockerfile")
        .arg("purify")
        .arg(input_file.path())
        .arg("-o")
        .arg(&output_file)
        .assert()
        .success();

    let purified = fs::read_to_string(&output_file).expect("Failed to read purified file");

    // Verify all comments are preserved
    assert!(purified.contains("# Base image"));
    assert!(purified.contains("# Update and install packages"));
    assert!(purified.contains("# Copy application files"));

    // Verify transformations still applied
    assert!(!purified.contains("ubuntu:latest"));
}

// ============================================================================
// Integration Test 6: Complex Multi-Line RUN Commands
// ============================================================================

#[test]
fn test_integration_complex_multiline_run() {
    // Test transformation of complex multi-line RUN commands
    let dockerfile = r#"FROM ubuntu:latest
RUN apt-get update && \
    apt-get install -y \
        curl \
        wget \
        git && \
    rm -rf /var/cache/apt/*
"#;

    let input_file = create_temp_dockerfile(dockerfile);
    let output_dir = TempDir::new().expect("Failed to create temp dir");
    let output_file = output_dir.path().join("Dockerfile");

    bashrs_cmd()
        .arg("dockerfile")
        .arg("purify")
        .arg(input_file.path())
        .arg("-o")
        .arg(&output_file)
        .assert()
        .success();

    let purified = fs::read_to_string(&output_file).expect("Failed to read purified file");

    // NOTE: Multi-line RUN commands with backslash continuations are NOT transformed
    // This is a known architectural limitation of line-by-line processing (see commands.rs:1072-1105)
    // Similar to Issue #2, would require preprocessing to handle continuation lines
    //
    // Current behavior: Multi-line commands are preserved but NOT transformed
    // Verify the multi-line structure is preserved (not broken)
    assert!(
        purified.contains("apt-get update && \\"),
        "Multi-line structure should be preserved"
    );
    assert!(
        purified.contains("apt-get install -y \\"),
        "Multi-line continuation should be preserved"
    );

    // FROM transformation still works (single-line)
    assert!(!purified.contains("ubuntu:latest"));
}

// ============================================================================
// Integration Test 7: Alpine Linux (apk) Workflow
// ============================================================================

#[test]
fn test_integration_alpine_apk_workflow() {
    // Test complete workflow with Alpine Linux and apk package manager
    let dockerfile = r#"FROM alpine:latest
RUN apk update && apk add curl wget
COPY app.sh /app/
"#;

    let input_file = create_temp_dockerfile(dockerfile);
    let output_dir = TempDir::new().expect("Failed to create temp dir");
    let output_file = output_dir.path().join("Dockerfile");

    bashrs_cmd()
        .arg("dockerfile")
        .arg("purify")
        .arg(input_file.path())
        .arg("-o")
        .arg(&output_file)
        .assert()
        .success();

    let purified = fs::read_to_string(&output_file).expect("Failed to read purified file");

    // Verify Alpine-specific transformations
    assert!(!purified.contains("alpine:latest"));
    assert!(purified.contains("/var/cache/apk"));
}

// ============================================================================
// Integration Test 8: Empty Dockerfile
// ============================================================================

#[test]
fn test_integration_empty_dockerfile() {
    // Test handling of empty/minimal Dockerfiles
    let dockerfile = "# Just a comment\n";

    let input_file = create_temp_dockerfile(dockerfile);
    let output_dir = TempDir::new().expect("Failed to create temp dir");
    let output_file = output_dir.path().join("Dockerfile");

    bashrs_cmd()
        .arg("dockerfile")
        .arg("purify")
        .arg(input_file.path())
        .arg("-o")
        .arg(&output_file)
        .assert()
        .success();

    let purified = fs::read_to_string(&output_file).expect("Failed to read purified file");

    // Verify comment is preserved
    assert!(purified.contains("# Just a comment"));
}

// ============================================================================
// Integration Test 9: Determinism Verification
// ============================================================================

#[test]
fn test_integration_determinism_multiple_runs() {
    // Verify that multiple purifications produce identical byte-for-byte results
    let dockerfile = r#"FROM ubuntu:latest
RUN apt-get update && apt-get install -y nginx curl
ADD local.txt /app/
"#;

    let input_file = create_temp_dockerfile(dockerfile);
    let temp_dir = TempDir::new().expect("Failed to create temp dir");

    // Run purification 3 times
    let mut outputs = Vec::new();
    for i in 0..3 {
        let output = temp_dir.path().join(format!("Dockerfile.purified{}", i));
        bashrs_cmd()
            .arg("dockerfile")
            .arg("purify")
            .arg(input_file.path())
            .arg("-o")
            .arg(&output)
            .assert()
            .success();

        let content = fs::read_to_string(&output).expect("Failed to read purified file");
        outputs.push(content);
    }

    // Verify all 3 outputs are identical
    assert_eq!(
        outputs[0], outputs[1],
        "Run 1 and 2 should produce identical results"
    );
    assert_eq!(
        outputs[1], outputs[2],
        "Run 2 and 3 should produce identical results"
    );
}

// ============================================================================
// Integration Test 10: Large Dockerfile Performance
// ============================================================================

#[test]
fn test_integration_large_dockerfile_performance() {
    // Test performance with a large Dockerfile (50+ instructions)
    let mut dockerfile = String::from("FROM ubuntu:latest\n");
    for i in 0..50 {
        dockerfile.push_str(&format!("RUN apt-get install -y package{}\n", i));
    }

    let input_file = create_temp_dockerfile(&dockerfile);
    let output_dir = TempDir::new().expect("Failed to create temp dir");
    let output_file = output_dir.path().join("Dockerfile");

    // Verify purification completes successfully (performance test)
    bashrs_cmd()
        .arg("dockerfile")
        .arg("purify")
        .arg(input_file.path())
        .arg("-o")
        .arg(&output_file)
        .assert()
        .success();

    let purified = fs::read_to_string(&output_file).expect("Failed to read purified file");

    // Verify all transformations applied to all RUN commands
    assert_eq!(
        purified.matches("--no-install-recommends").count(),
        50,
        "All 50 RUN commands should have --no-install-recommends"
    );
}
