#!/bin/bash

# Automatic setup script for Test-Driven Development (TDD)
# This script sets up everything needed to start TDD in various programming languages
# Author: PAELLADOC
# Version: 1.2

# Colors for better readability
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
NC='\033[0m' # No Color

echo -e "${BLUE}=====================================${NC}"
echo -e "${BLUE}      AUTOMATIC TDD SETUP          ${NC}"
echo -e "${BLUE}=====================================${NC}"

# Function to set up a Node.js/TypeScript project
setup_node() {
  echo -e "\n${BLUE}Setting up Node.js/TypeScript project...${NC}"
  
  # Check if we're in a Node project
  if [ ! -f package.json ]; then
    echo -e "${YELLOW}package.json not found. Do you want to initialize a new project? [y/n]${NC}"
    read -r response
    if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then
      echo -e "${GREEN}Initializing new project...${NC}"
      npm init -y
    else
      echo -e "${RED}Cannot continue without a Node project. Aborting.${NC}"
      return 1
    fi
  fi

  # Install basic dependencies
  echo -e "\n${BLUE}Installing development dependencies...${NC}"
  npm install --save-dev typescript ts-node

  # Install testing tools
  echo -e "\n${BLUE}Installing testing tools...${NC}"
  npm install --save-dev jest ts-jest @types/jest

  # Configure TypeScript if it doesn't exist
  if [ ! -f tsconfig.json ]; then
    echo -e "\n${BLUE}Configuring TypeScript...${NC}"
    npx tsc --init --target es2017 --module commonjs --esModuleInterop true --forceConsistentCasingInFileNames true --strict true --skipLibCheck true
  fi

  # Create Jest configuration
  echo -e "\n${BLUE}Creating Jest configuration...${NC}"
  cat > jest.config.js << 'EOL'
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  roots: ['<rootDir>/src'],
  testMatch: ['**/*.test.ts'],
  collectCoverage: true,
  coverageDirectory: 'coverage',
  collectCoverageFrom: ['src/**/*.ts', '!src/**/*.d.ts'],
};
EOL

  # Configure scripts in package.json
  echo -e "\n${BLUE}Configuring scripts in package.json...${NC}"
  npm pkg set "scripts.test=jest" "scripts.test:watch=jest --watch" "scripts.test:coverage=jest --coverage"

  # Create file structure
  echo -e "\n${BLUE}Creating directory structure...${NC}"
  mkdir -p src

  # Create initial test file
  echo -e "\n${BLUE}Creating initial test file...${NC}"
  cat > src/initial.test.ts << 'EOL'
describe('Initial configuration test', () => {
  it('should pass to verify that Jest is configured correctly', () => {
    expect(true).toBe(true);
  });
});
EOL

  # Run initial test
  echo -e "\n${BLUE}Running initial test to verify configuration...${NC}"
  npm test

  # Create example if requested
  create_node_example
}

# Function to create Node.js example
create_node_example() {
  echo -e "\n${BLUE}Do you want to create a function example with TDD? [y/n]${NC}"
  read -r create_example
  if [[ "$create_example" =~ ^([yY][eE][sS]|[yY])$ ]]; then
    echo -e "${GREEN}Creating TDD example...${NC}"
    
    # Create test file
    cat > src/example.test.ts << 'EOL'
import { sum } from './example';

describe('Sum function', () => {
  it('should correctly add two positive numbers', () => {
    expect(sum(2, 3)).toBe(5);
  });
  
  it('should handle negative numbers', () => {
    expect(sum(-1, 1)).toBe(0);
    expect(sum(-1, -1)).toBe(-2);
  });
  
  it('should handle zero', () => {
    expect(sum(0, 5)).toBe(5);
    expect(sum(5, 0)).toBe(5);
    expect(sum(0, 0)).toBe(0);
  });
});
EOL

    # Create implementation file
    cat > src/example.ts << 'EOL'
/**
 * Adds two numbers and returns the result
 * @param a First number
 * @param b Second number
 * @returns The sum of a and b
 */
export function sum(a: number, b: number): number {
  return a + b;
}
EOL

    echo -e "${GREEN}Example created. Running example tests...${NC}"
    npm test
  fi
}

# Function to set up a Python project
setup_python() {
  echo -e "\n${BLUE}Setting up Python project...${NC}"

  # Check for python
  if ! command -v python3 &> /dev/null; then
    echo -e "${RED}Python 3 is not installed. Please install it first.${NC}"
    return 1
  fi

  # Create virtual environment
  echo -e "\n${BLUE}Creating virtual environment...${NC}"
  python3 -m venv venv
  
  # Activate virtual environment
  if [[ "$OSTYPE" == "darwin"* ]] || [[ "$OSTYPE" == "linux-gnu"* ]]; then
    source venv/bin/activate
  elif [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then
    source venv/Scripts/activate
  else
    echo -e "${YELLOW}Could not automatically activate virtual environment.${NC}"
    echo -e "${YELLOW}Please activate it manually before continuing.${NC}"
  fi

  # Install testing tools
  echo -e "\n${BLUE}Installing testing tools...${NC}"
  pip install pytest pytest-cov

  # Create directory structure
  echo -e "\n${BLUE}Creating directory structure...${NC}"
  mkdir -p src tests

  # Create initial test file
  echo -e "\n${BLUE}Creating initial test file...${NC}"
  cat > tests/test_initial.py << 'EOL'
def test_initial_configuration():
    """Verify pytest is configured correctly."""
    assert True
EOL

  # Create pytest.ini
  echo -e "\n${BLUE}Creating pytest configuration...${NC}"
  cat > pytest.ini << 'EOL'
[pytest]
testpaths = tests
python_files = test_*.py
python_functions = test_*
EOL

  # Run initial test
  echo -e "\n${BLUE}Running initial test to verify configuration...${NC}"
  python -m pytest tests/

  # Create example if requested
  create_python_example
}

# Function to create Python example
create_python_example() {
  echo -e "\n${BLUE}Do you want to create a function example with TDD? [y/n]${NC}"
  read -r create_example
  if [[ "$create_example" =~ ^([yY][eE][sS]|[yY])$ ]]; then
    echo -e "${GREEN}Creating TDD example...${NC}"
    
    # Create test file
    cat > tests/test_calculator.py << 'EOL'
from src.calculator import sum_numbers

def test_sum_positive_numbers():
    """Test that the sum function can add positive numbers."""
    assert sum_numbers(2, 3) == 5

def test_sum_negative_numbers():
    """Test that the sum function can handle negative numbers."""
    assert sum_numbers(-1, 1) == 0
    assert sum_numbers(-1, -1) == -2

def test_sum_with_zero():
    """Test that the sum function works with zero."""
    assert sum_numbers(0, 5) == 5
    assert sum_numbers(5, 0) == 5
    assert sum_numbers(0, 0) == 0
EOL

    # Create module directory if it doesn't exist
    mkdir -p src

    # Create __init__.py to make it a proper package
    touch src/__init__.py

    # Create implementation file
    cat > src/calculator.py << 'EOL'
def sum_numbers(a, b):
    """
    Add two numbers and return the result.
    
    Args:
        a: First number
        b: Second number
        
    Returns:
        The sum of a and b
    """
    return a + b
EOL

    echo -e "${GREEN}Example created. Running example tests...${NC}"
    python -m pytest tests/
  fi
}

# Function to set up a Java project (Maven)
setup_java() {
  echo -e "\n${BLUE}Setting up Java project...${NC}"

  # Check for Java
  if ! command -v java &> /dev/null; then
    echo -e "${RED}Java is not installed. Please install it first.${NC}"
    return 1
  fi

  # Check for Maven
  if ! command -v mvn &> /dev/null; then
    echo -e "${RED}Maven is not installed. Please install it first.${NC}"
    return 1
  fi

  # Create Maven project
  echo -e "\n${BLUE}Creating Maven project...${NC}"
  mvn archetype:generate \
    -DgroupId=com.example \
    -DartifactId=tdd-project \
    -DarchetypeArtifactId=maven-archetype-quickstart \
    -DarchetypeVersion=1.4 \
    -DinteractiveMode=false

  # Change to project directory
  cd tdd-project

  # Update pom.xml to use JUnit 5
  echo -e "\n${BLUE}Updating POM to use JUnit 5...${NC}"
  sed -i.bak '/<dependencies>/,/<\/dependencies>/c\
  <dependencies>\
    <dependency>\
      <groupId>org.junit.jupiter</groupId>\
      <artifactId>junit-jupiter</artifactId>\
      <version>5.8.2</version>\
      <scope>test</scope>\
    </dependency>\
  </dependencies>\
  <build>\
    <plugins>\
      <plugin>\
        <groupId>org.apache.maven.plugins</groupId>\
        <artifactId>maven-surefire-plugin</artifactId>\
        <version>0.1.0-M5</version>\
      </plugin>\
      <plugin>\
        <groupId>org.apache.maven.plugins</groupId>\
        <artifactId>maven-compiler-plugin</artifactId>\
        <version>3.8.1</version>\
        <configuration>\
          <source>11</source>\
          <target>11</target>\
        </configuration>\
      </plugin>\
    </plugins>\
  </build>' pom.xml

  # Update App test to use JUnit 5
  echo -e "\n${BLUE}Updating initial test to use JUnit 5...${NC}"
  cat > src/test/java/com/example/AppTest.java << 'EOL'
package com.example;

import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;

public class AppTest {
    @Test
    public void initialConfigurationTest() {
        assertTrue(true, "JUnit 5 is configured correctly");
    }
}
EOL

  # Run initial test
  echo -e "\n${BLUE}Running initial test to verify configuration...${NC}"
  mvn test

  # Create example if requested
  create_java_example
}

# Function to create Java example
create_java_example() {
  echo -e "\n${BLUE}Do you want to create a function example with TDD? [y/n]${NC}"
  read -r create_example
  if [[ "$create_example" =~ ^([yY][eE][sS]|[yY])$ ]]; then
    echo -e "${GREEN}Creating TDD example...${NC}"
    
    # Create test file
    cat > src/test/java/com/example/CalculatorTest.java << 'EOL'
package com.example;

import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;

public class CalculatorTest {
    @Test
    public void shouldAddPositiveNumbers() {
        Calculator calculator = new Calculator();
        assertEquals(5, calculator.sum(2, 3), "Should correctly add two positive numbers");
    }
    
    @Test
    public void shouldHandleNegativeNumbers() {
        Calculator calculator = new Calculator();
        assertEquals(0, calculator.sum(-1, 1), "Should handle negative with positive");
        assertEquals(-2, calculator.sum(-1, -1), "Should handle negative with negative");
    }
    
    @Test
    public void shouldHandleZero() {
        Calculator calculator = new Calculator();
        assertEquals(5, calculator.sum(5, 0), "Should handle zero as second param");
        assertEquals(5, calculator.sum(0, 5), "Should handle zero as first param");
        assertEquals(0, calculator.sum(0, 0), "Should handle zero for both params");
    }
}
EOL

    # Create implementation file
    cat > src/main/java/com/example/Calculator.java << 'EOL'
package com.example;

/**
 * Simple calculator class for TDD demonstration
 */
public class Calculator {
    /**
     * Adds two numbers and returns the result
     * 
     * @param a First number
     * @param b Second number
     * @return Sum of a and b
     */
    public int sum(int a, int b) {
        return a + b;
    }
}
EOL

    echo -e "${GREEN}Example created. Running example tests...${NC}"
    mvn test
  fi
}

# Function to set up a Ruby project
setup_ruby() {
  echo -e "\n${BLUE}Setting up Ruby project...${NC}"

  # Check for Ruby
  if ! command -v ruby &> /dev/null; then
    echo -e "${RED}Ruby is not installed. Please install it first.${NC}"
    return 1
  fi

  # Check for Bundler
  if ! command -v bundle &> /dev/null; then
    echo -e "${YELLOW}Bundler is not installed. Installing Bundler...${NC}"
    gem install bundler
    if [ $? -ne 0 ]; then
      echo -e "${RED}Failed to install Bundler. Please check your Ruby installation.${NC}"
      return 1
    fi
  fi

  # Create project directory if we're not already in a Ruby project
  if [ ! -f Gemfile ]; then
    echo -e "${YELLOW}Gemfile not found. Creating a new Ruby project...${NC}"
    
    # Create Gemfile
    cat > Gemfile << 'EOL'
source 'https://rubygems.org'

gem 'rspec', '~> 3.12'
gem 'simplecov', '~> 0.22.0', require: false
EOL
  fi

  # Install dependencies
  echo -e "\n${BLUE}Installing dependencies with Bundler...${NC}"
  bundle install

  # Initialize RSpec
  echo -e "\n${BLUE}Initializing RSpec...${NC}"
  mkdir -p spec
  bundle exec rspec --init

  # Update spec_helper.rb to add SimpleCov
  cat >> spec/spec_helper.rb << 'EOL'

# Enable code coverage with SimpleCov
require 'simplecov'
SimpleCov.start do
  add_filter '/spec/'
end
EOL

  # Create project structure
  echo -e "\n${BLUE}Creating project structure...${NC}"
  mkdir -p lib

  # Create initial test file
  echo -e "\n${BLUE}Creating initial test file...${NC}"
  cat > spec/initial_spec.rb << 'EOL'
require 'spec_helper'

describe 'Initial configuration' do
  it 'verifies that RSpec is configured correctly' do
    expect(true).to be true
  end
end
EOL

  # Run initial test
  echo -e "\n${BLUE}Running initial test to verify configuration...${NC}"
  bundle exec rspec spec/initial_spec.rb

  # Create example if requested
  create_ruby_example
}

# Function to create Ruby example
create_ruby_example() {
  echo -e "\n${BLUE}Do you want to create a function example with TDD? [y/n]${NC}"
  read -r create_example
  if [[ "$create_example" =~ ^([yY][eE][sS]|[yY])$ ]]; then
    echo -e "${GREEN}Creating TDD example...${NC}"

    # Create test file
    cat > spec/calculator_spec.rb << 'EOL'
require 'spec_helper'
require_relative '../lib/calculator'

describe Calculator do
  describe '#sum' do
    let(:calculator) { Calculator.new }

    it 'correctly adds two positive numbers' do
      expect(calculator.sum(2, 3)).to eq(5)
    end

    it 'handles negative numbers' do
      expect(calculator.sum(-1, 1)).to eq(0)
      expect(calculator.sum(-1, -1)).to eq(-2)
    end

    it 'handles zero' do
      expect(calculator.sum(0, 5)).to eq(5)
      expect(calculator.sum(5, 0)).to eq(5)
      expect(calculator.sum(0, 0)).to eq(0)
    end
  end
end
EOL

    # Create implementation file
    cat > lib/calculator.rb << 'EOL'
# Calculator class for TDD demonstration
class Calculator
  # Adds two numbers and returns the result
  #
  # @param a [Numeric] First number
  # @param b [Numeric] Second number
  # @return [Numeric] Sum of a and b
  def sum(a, b)
    a + b
  end
end
EOL

    echo -e "${GREEN}Example created. Running example tests...${NC}"
    bundle exec rspec spec/calculator_spec.rb
  fi
}

# Select language
select_language() {
  echo -e "${PURPLE}Select the programming language for your TDD project:${NC}"
  echo -e "${YELLOW}1. Node.js/TypeScript${NC}"
  echo -e "${YELLOW}2. Python${NC}"
  echo -e "${YELLOW}3. Java${NC}"
  echo -e "${YELLOW}4. Ruby${NC}"
  read -r lang_choice

  case $lang_choice in
    1)
      setup_node
      ;;
    2)
      setup_python
      ;;
    3)
      setup_java
      ;;
    4)
      setup_ruby
      ;;
    *)
      echo -e "${RED}Invalid choice. Please select a valid option.${NC}"
      select_language
      ;;
  esac
}

# Main execution
select_language

# Success message
if [ $? -eq 0 ]; then
  echo -e "\n${GREEN}==================================================${NC}"
  echo -e "${GREEN}     TDD CONFIGURATION COMPLETED SUCCESSFULLY!     ${NC}"
  echo -e "${GREEN}==================================================${NC}"
  echo -e "\n${BLUE}Happy coding with TDD!${NC}"
else
  echo -e "\n${RED}==================================================${NC}"
  echo -e "${RED}ERROR: Configuration was not completed successfully${NC}"
  echo -e "${RED}==================================================${NC}"
  echo -e "\nPlease review the error messages above."
fi 