package tests

import (
	"os"
	"path/filepath"
	"testing"

	"github.com/jfraeys/fetch_ml/internal/fileutil"
)

// TestZeroInstallWorkflow tests the complete minimal zero-install workflow
func TestZeroInstallWorkflow(t *testing.T) {
	t.Parallel() // Enable parallel execution

	// Setup test environment
	testDir := t.TempDir()

	// Step 1: Create experiment locally (simulating DS workflow)
	experimentDir := filepath.Join(testDir, "my_experiment")
	if err := os.MkdirAll(experimentDir, 0750); err != nil {
		t.Fatalf("Failed to create experiment directory: %v", err)
	}

	// Create train.py (simplified from README example)
	trainScript := filepath.Join(experimentDir, "train.py")
	trainCode := `import argparse, json, logging, time
from pathlib import Path

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--epochs", type=int, default=10)
    parser.add_argument("--output_dir", type=str, required=True)
    args = parser.parse_args()
    
    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger(__name__)
    
    logger.info(f"Training for {args.epochs} epochs...")
    
    for epoch in range(args.epochs):
        loss = 1.0 - (epoch * 0.1)
        accuracy = 0.5 + (epoch * 0.045)
        logger.info(f"Epoch {epoch + 1}: loss={loss:.4f}, acc={accuracy:.4f}")
        time.sleep(0.1) // Reduced from 0.5
    
    results = {"accuracy": accuracy, "loss": loss, "epochs": args.epochs}
    
    output_dir = Path(args.output_dir)
    output_dir.mkdir(parents=True, exist_ok=True)
    
    with open(output_dir / "results.json", "w") as f:
        json.dump(results, f)
    
    logger.info("Training complete!")

if __name__ == "__main__":
    main()
`

	//nolint:gosec // G306: Script needs execute permissions
	if err := os.WriteFile(trainScript, []byte(trainCode), 0750); err != nil {
		t.Fatalf("Failed to create train.py: %v", err)
	}

	// Test 1: Verify experiment structure (Step 1 validation)
	t.Run("Step1_CreateExperiment", func(t *testing.T) {
		// Check train.py exists and is executable
		if _, err := os.Stat(trainScript); os.IsNotExist(err) {
			t.Error("train.py should exist after experiment creation")
		}

		info, err := os.Stat(trainScript)
		if err != nil {
			t.Fatalf("Failed to stat train.py: %v", err)
		}
		if info.Mode().Perm()&0111 == 0 {
			t.Error("train.py should be executable")
		}
	})

	// Step 2: Simulate upload process (rsync simulation)
	t.Run("Step2_UploadExperiment", func(t *testing.T) {
		// Create server directory structure (simulate ml-server.company.com)
		serverDir := filepath.Join(testDir, "server")
		homeDir := filepath.Join(serverDir, "home", "mluser")
		pendingDir := filepath.Join(homeDir, "ml_jobs", "pending")

		// Generate timestamp-based job name (simulating workflow)
		jobName := "my_experiment_20231201_143022"
		jobDir := filepath.Join(pendingDir, jobName)

		if err := os.MkdirAll(jobDir, 0750); err != nil {
			t.Fatalf("Failed to create server directories: %v", err)
		}

		// Simulate rsync upload (copy experiment files)
		files := []string{"train.py"}
		for _, file := range files {
			src := filepath.Join(experimentDir, file)
			dst := filepath.Join(jobDir, file)

			data, err := fileutil.SecureFileRead(src)
			if err != nil {
				t.Fatalf("Failed to read %s: %v", file, err)
			}

			//nolint:gosec // G306: Script needs execute permissions
			if err := os.WriteFile(dst, data, 0750); err != nil {
				t.Fatalf("Failed to copy %s: %v", file, err)
			}
		}

		// Verify upload succeeded
		for _, file := range files {
			dst := filepath.Join(jobDir, file)
			if _, err := os.Stat(dst); os.IsNotExist(err) {
				t.Errorf("Uploaded file %s should exist in pending directory", file)
			}
		}

		// Verify job directory structure
		if _, err := os.Stat(pendingDir); os.IsNotExist(err) {
			t.Error("Pending directory should exist")
		}
		if _, err := os.Stat(jobDir); os.IsNotExist(err) {
			t.Error("Job directory should exist")
		}
	})

	// Step 3: Simulate TUI access (minimal - just verify TUI would launch)
	t.Run("Step3_TUIAccess", func(t *testing.T) {
		// Create fetch_ml directory structure (simulating server setup)
		serverDir := filepath.Join(testDir, "server")
		fetchMlDir := filepath.Join(serverDir, "home", "mluser", "fetch_ml")
		buildDir := filepath.Join(fetchMlDir, "build")
		configsDir := filepath.Join(fetchMlDir, "configs")

		if err := os.MkdirAll(buildDir, 0750); err != nil {
			t.Fatalf("Failed to create fetch_ml directories: %v", err)
		}
		if err := os.MkdirAll(configsDir, 0750); err != nil {
			t.Fatalf("Failed to create configs directory: %v", err)
		}

		// Create mock TUI binary
		tuiBinary := filepath.Join(buildDir, "tui")
		tuiContent := "#!/bin/bash\necho 'Mock TUI would launch here'"
		//nolint:gosec // G306: Script needs execute permissions
		if err := os.WriteFile(tuiBinary, []byte(tuiContent), 0750); err != nil {
			t.Fatalf("Failed to create mock TUI binary: %v", err)
		}

		// Create config file
		configFile := filepath.Join(configsDir, "config.yaml")
		configContent := `server:
  host: "localhost"
  port: 8080

redis:
  addr: "localhost:6379"
  db: 0

data_dir: "/home/mluser/datasets"
output_dir: "/home/mluser/ml_jobs"
`
		if err := os.WriteFile(configFile, []byte(configContent), 0600); err != nil {
			t.Fatalf("Failed to create config file: %v", err)
		}

		// Verify TUI setup
		if _, err := os.Stat(tuiBinary); os.IsNotExist(err) {
			t.Error("TUI binary should exist")
		}
		if _, err := os.Stat(configFile); os.IsNotExist(err) {
			t.Error("Config file should exist")
		}
	})

	// Test: Verify complete workflow files exist
	t.Run("CompleteWorkflowValidation", func(t *testing.T) {
		// Verify experiment files exist
		if _, err := os.Stat(trainScript); os.IsNotExist(err) {
			t.Error("Experiment train.py should exist")
		}

		// Verify uploaded files exist
		uploadedTrainScript := filepath.Join(
			testDir, "server", "home", "mluser", "ml_jobs", "pending",
			"my_experiment_20231201_143022", "train.py")
		if _, err := os.Stat(uploadedTrainScript); os.IsNotExist(err) {
			t.Error("Uploaded train.py should exist in pending directory")
		}

		// Verify TUI setup exists
		tuiBinary := filepath.Join(testDir, "server", "home", "mluser", "fetch_ml", "build", "tui")
		if _, err := os.Stat(tuiBinary); os.IsNotExist(err) {
			t.Error("TUI binary should exist for workflow completion")
		}
	})
}

// TestMinimalWorkflowSecurity tests security aspects of minimal workflow
func TestMinimalWorkflowSecurity(t *testing.T) {
	t.Parallel() // Enable parallel execution
	testDir := t.TempDir()

	// Create mock SSH environment
	sshRc := filepath.Join(testDir, "sshrc")
	sshRcContent := `#!/bin/bash
# Mock SSH rc - TUI only
if [ -n "$SSH_CONNECTION" ] && [ -z "$SSH_ORIGINAL_COMMAND" ]; then
    echo "TUI would launch here"
else
    echo "Command execution blocked for security"
    exit 1
fi
`

	//nolint:gosec // G306: Script needs execute permissions
	if err := os.WriteFile(sshRc, []byte(sshRcContent), 0750); err != nil {
		t.Fatalf("Failed to create SSH rc: %v", err)
	}

	t.Run("TUIOnlyAccess", func(t *testing.T) {
		// Verify SSH rc exists and is executable
		if _, err := os.Stat(sshRc); os.IsNotExist(err) {
			t.Error("SSH rc should exist")
		}

		info, err := os.Stat(sshRc)
		if err != nil {
			t.Fatalf("Failed to stat SSH rc: %v", err)
		}
		if info.Mode().Perm()&0111 == 0 {
			t.Error("SSH rc should be executable")
		}
	})
}
