#!/bin/bash

# InvoiceShelf Development Environment Startup Script
# Supports Linux and macOS

set -e

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

# Function to print colored output
print_info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

print_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}

print_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# Function to show usage
show_usage() {
    echo "Usage: $0 [COMMAND]"
    echo ""
    echo "Commands:"
    echo "  (no command)  Start the development environment (interactive setup)"
    echo "  start         Start the development environment with existing configuration"
    echo "  stop          Stop the development environment"
    echo "  destroy       Stop and remove containers, networks, and images"
    echo "  logs          Show logs from all services"
    echo "  rebuild       Rebuild and restart the development environment"
    echo "  shell         Enter the PHP container's shell"
    echo "  run [CMD]     Run a command inside the PHP container (e.g., ./artisan)"
    echo "  test          Run the test suite (Pest)"
    echo "  format        Format the code (Pint)"
    echo ""
    echo "Examples:"
    echo "  $0            # Interactive setup and start"
    echo "  $0 start      # Start with last used configuration"
    echo "  $0 stop       # Stop all services"
    echo "  $0 logs       # View logs"
    echo "  $0 shell      # Get a shell inside the PHP container"
    echo "  $0 run ./artisan --help"
}

# Function to detect OS
detect_os() {
    case "$(uname -s)" in
        Linux*)     echo "linux";;
        Darwin*)    echo "mac";;
        *)          echo "unsupported";;
    esac
}

# Function to get docker compose command
get_docker_compose_cmd() {
    if command -v docker-compose &> /dev/null; then
        echo "docker-compose"
    else
        echo "docker compose"
    fi
}

# Function to find the most recent compose file used
find_compose_file() {
    local config_file=".devenvconfig"

    if [ -f "$config_file" ]; then
        cat "$config_file"
    else
        echo ""
    fi
}

# Function to save compose file configuration
save_config() {
    local compose_file=$1
    echo "$compose_file" > .devenvconfig
}

# Function to check if host entry exists
check_host_entry() {
    if grep -q "invoiceshelf.test" /etc/hosts; then
        return 0
    else
        return 1
    fi
}

# Function to add host entry
add_host_entry() {
    local os_type=$1

    print_info "Adding invoiceshelf.test to /etc/hosts..."

    if [ "$os_type" = "linux" ] || [ "$os_type" = "mac" ]; then
        # Check if we can write to /etc/hosts
        if [ ! -w /etc/hosts ]; then
            print_warning "Root permissions required to modify /etc/hosts"
            if sudo sh -c 'echo "127.0.0.1    invoiceshelf.test" >> /etc/hosts'; then
                print_success "Host entry added successfully"
            else
                print_error "Failed to add host entry"
                exit 1
            fi
        else
            echo "127.0.0.1    invoiceshelf.test" >> /etc/hosts
            print_success "Host entry added successfully"
        fi
    fi
}

# Function to select database type
select_database() {
    echo "" >&2
    print_info "Select database type:" >&2
    echo "1) MySQL/MariaDB" >&2
    echo "2) PostgreSQL" >&2
    echo "3) SQLite" >&2

    while true; do
        read -p "Enter your choice (1-3): " db_choice
        case $db_choice in
            1) echo "mysql"; break;;
            2) echo "pgsql"; break;;
            3) echo "sqlite"; break;;
            *) print_error "Invalid choice. Please enter 1, 2, or 3." >&2;;
        esac
    done
}

# Function to ask about gotenberg
ask_gotenberg() {
    echo "" >&2
    print_info "Do you want to use Gotenberg for PDF generation?" >&2
    print_info "Gotenberg provides better PDF generation capabilities but requires more resources." >&2

    while true; do
        read -p "Use Gotenberg? (y/n): " gotenberg_choice
        case $gotenberg_choice in
            [Yy]* ) echo "yes"; break;;
            [Nn]* ) echo "no"; break;;
            * ) print_error "Please answer yes (y) or no (n)." >&2;;
        esac
    done
}

# Function to validate environment
validate_environment() {
    # Detect OS
    local os_type=$(detect_os)

    if [ "$os_type" = "unsupported" ]; then
        print_error "Unsupported operating system. This script only supports Linux and macOS."
        exit 1
    fi

    # Check if Docker is installed
    if ! command -v docker &> /dev/null; then
        print_error "Docker is not installed. Please install Docker first."
        echo ""
        print_info "Installation instructions:"
        if [ "$os_type" = "linux" ]; then
            echo "  • Ubuntu/Debian: https://docs.docker.com/engine/install/ubuntu/"
            echo "  • CentOS/RHEL: https://docs.docker.com/engine/install/centos/"
            echo "  • Fedora: https://docs.docker.com/engine/install/fedora/"
        else
            echo "  • macOS: https://docs.docker.com/desktop/mac/install/"
        fi
        exit 1
    fi

    # Check if Docker daemon is running
    print_info "Checking Docker daemon status..."
    if ! docker info &> /dev/null; then
        print_error "Docker daemon is not running."
        echo ""
        print_info "To start Docker:"
        if [ "$os_type" = "linux" ]; then
            echo "  • systemctl start docker"
            echo "  • sudo systemctl start docker (if not in docker group)"
            echo "  • Or start Docker Desktop if using it"
        else
            echo "  • Start Docker Desktop application"
            echo "  • Or run: open -a Docker"
        fi
        exit 1
    fi

    # Check Docker daemon connectivity and permissions
    if ! docker ps &> /dev/null; then
        print_error "Cannot connect to Docker daemon. Permission denied."
        echo ""
        print_info "This might be a permissions issue. Try:"
        if [ "$os_type" = "linux" ]; then
            echo "  • sudo usermod -aG docker \$USER"
            echo "  • Log out and log back in"
            echo "  • Or run the script with sudo (not recommended)"
        else
            echo "  • Restart Docker Desktop"
            echo "  • Check Docker Desktop settings"
        fi
        exit 1
    fi

    # Check if Docker Compose is available
    local compose_available=false
    local compose_cmd=""

    if command -v docker-compose &> /dev/null; then
        if docker-compose version &> /dev/null; then
            compose_available=true
            compose_cmd="docker-compose"
        fi
    fi

    if ! $compose_available && docker compose version &> /dev/null 2>&1; then
        compose_available=true
        compose_cmd="docker compose"
    fi

    if ! $compose_available; then
        print_error "Docker Compose is not available or not working properly."
        echo ""
        print_info "Installation instructions:"
        if [ "$os_type" = "linux" ]; then
            echo "  • Install docker-compose: sudo apt-get install docker-compose"
            echo "  • Or use Docker Compose V2: https://docs.docker.com/compose/install/"
        else
            echo "  • Docker Compose should be included with Docker Desktop"
            echo "  • Try restarting Docker Desktop"
        fi
        exit 1
    fi

    # Check available system resources
    print_info "Checking system resources..."

    # Check available disk space (require at least 2GB free)
    local available_space
    if [ "$os_type" = "linux" ]; then
        available_space=$(df / | awk 'NR==2 {print $4}')
    else
        available_space=$(df / | awk 'NR==2 {print $4}')
    fi

    # Convert KB to GB (approximate)
    local available_gb=$((available_space / 1024 / 1024))

    if [ $available_gb -lt 2 ]; then
        print_warning "Low disk space detected: ${available_gb}GB available"
        print_warning "Docker images and containers require significant disk space"
        read -p "Continue anyway? (y/N): " continue_choice
        case $continue_choice in
            [Yy]* ) ;;
            * ) print_info "Operation cancelled."; exit 1;;
        esac
    fi

    # Check if Docker has enough resources allocated (for Docker Desktop)
    if [ "$os_type" = "mac" ] || ([ "$os_type" = "linux" ] && command -v docker-desktop &> /dev/null); then
        print_info "Detected Docker Desktop - ensure adequate resources are allocated"
        print_info "Recommended: 4GB RAM, 2 CPU cores, 20GB disk space"
    fi

    print_success "Docker environment validation completed"
}

# Function to get compose file for subcommands
get_compose_file_for_cmd() {
    local compose_file=$(find_compose_file)

    if [ -z "$compose_file" ] || [ ! -f "$compose_file" ]; then
        print_error "No previous configuration found. Please run the script without arguments first to set up the environment."
        exit 1
    fi

    echo "$compose_file"
}

# Subcommand functions
cmd_start() {
    print_info "Starting development environment..."

    local compose_file=$(get_compose_file_for_cmd)
    local docker_compose=$(get_docker_compose_cmd)

    print_info "Using compose file: $compose_file"

    if $docker_compose -f "$compose_file" up -d; then
        print_success "Development environment started successfully!"
        show_service_info
    else
        print_error "Failed to start development environment"
        exit 1
    fi
}

cmd_stop() {
    print_info "Stopping development environment..."

    local compose_file=$(get_compose_file_for_cmd)
    local docker_compose=$(get_docker_compose_cmd)

    if $docker_compose -f "$compose_file" down --remove-orphans; then
        print_success "Development environment stopped successfully!"
    else
        print_error "Failed to stop development environment"
        exit 1
    fi
}

cmd_destroy() {
    print_info "Destroying development environment (removing containers, networks, and images)..."

    local compose_file=$(get_compose_file_for_cmd)
    local docker_compose=$(get_docker_compose_cmd)

    print_warning "This will remove all containers, networks, and images for this project."
    read -p "Are you sure? (y/N): " confirm

    case $confirm in
        [Yy]* )
            if $docker_compose -f "$compose_file" down --rmi all --volumes --remove-orphans; then
                print_success "Development environment destroyed successfully!"
                # Remove the config file since everything is destroyed
                rm -f .devenvconfig
            else
                print_error "Failed to destroy development environment"
                exit 1
            fi
            ;;
        * )
            print_info "Operation cancelled."
            ;;
    esac
}

cmd_logs() {
    print_info "Showing logs from development environment..."

    local compose_file=$(get_compose_file_for_cmd)
    local docker_compose=$(get_docker_compose_cmd)

    # Check if any additional arguments were passed for specific services
    shift # Remove 'logs' from arguments

    if [ $# -gt 0 ]; then
        print_info "Showing logs for services: $*"
        $docker_compose -f "$compose_file" logs -f "$@"
    else
        print_info "Showing logs for all services (Press Ctrl+C to exit)"
        $docker_compose -f "$compose_file" logs -f
    fi
}

cmd_rebuild() {
    print_info "Rebuilding development environment..."

    local compose_file=$(get_compose_file_for_cmd)
    local docker_compose=$(get_docker_compose_cmd)

    print_info "Stopping services..."
    $docker_compose -f "$compose_file" down

    print_info "Rebuilding images..."
    if $docker_compose -f "$compose_file" build --no-cache; then
        print_info "Starting services..."
        if $docker_compose -f "$compose_file" up -d; then
            print_success "Development environment rebuilt and started successfully!"
            show_service_info
        else
            print_error "Failed to start development environment after rebuild"
            exit 1
        fi
    else
        print_error "Failed to rebuild development environment"
        exit 1
    fi
}

cmd_shell() {
    print_info "Entering PHP container shell..."

    # Check if the container is running first
    if ! docker ps --format "{{.Names}}" | grep -q "invoiceshelf-dev-php"; then
        print_error "PHP container 'invoiceshelf-dev-php' is not running."
        print_info "Start the development environment first with: $0 start"
        exit 1
    fi

    print_info "Connecting to invoiceshelf-dev-php container... Type 'exit' to leave."

    # Try /bin/bash first, fall back to /bin/sh if bash is not available
    if ! docker exec -it invoiceshelf-dev-php /bin/bash; then
        docker exec -it invoiceshelf-dev-php /bin/sh
    fi
    print_success "Exited from container shell."
}

cmd_run() {
    shift # Remove 'run' from arguments
    if [ $# -eq 0 ]; then
        print_error "No command provided to 'run'."
        show_usage
        exit 1
    fi

    print_info "Running command inside PHP container: $@"

    # Check if the container is running first
    if ! docker ps --format "{{.Names}}" | grep -q "invoiceshelf-dev-php"; then
        print_error "PHP container 'invoiceshelf-dev-php' is not running."
        print_info "Start the development environment first with: $0 start"
        exit 1
    fi

    docker exec -it -w /var/www/html invoiceshelf-dev-php "$@"
}

# Function to run tests
cmd_test() {
    print_info "Running tests (Pest)..."

    # Check if the container is running first
    if ! docker ps --format "{{.Names}}" | grep -q "invoiceshelf-dev-php"; then
        print_error "PHP container 'invoiceshelf-dev-php' is not running."
        print_info "Start the development environment first with: $0 start"
        exit 1
    fi

    shift # Remove 'test' from arguments
    docker exec -it -w /var/www/html invoiceshelf-dev-php /var/www/html/vendor/bin/pest "$@"
}

# Function to format code
cmd_format() {
    print_info "Formatting code (Pint)..."

    # Check if the container is running first
    if ! docker ps --format "{{.Names}}" | grep -q "invoiceshelf-dev-php"; then
        print_error "PHP container 'invoiceshelf-dev-php' is not running."
        print_info "Start the development environment first with: $0 start"
        exit 1
    fi

    shift # Remove 'format' from arguments
    docker exec -it -w /var/www/html invoiceshelf-dev-php /var/www/html/vendor/bin/pint "$@"
}

# Function to show service information
show_service_info() {
    echo ""
    print_info "Available services:"
    echo "  • Application: http://invoiceshelf.test"
    echo "  • Adminer (DB): http://localhost:8080"
    echo "  • Mailpit: http://localhost:8025"
    echo ""
    print_info "Useful commands:"
    echo "  • Stop: $0 stop"
    echo "  • View logs: $0 logs"
    echo "  • Rebuild: $0 rebuild"
    echo "  • Shell: $0 shell"
    echo "  • Run command: $0 run php artisan help"
}

# Main setup function (original functionality)
setup_environment() {
    print_info "InvoiceShelf Development Environment Setup"
    echo "=========================================="

    local os_type=$(detect_os)
    print_success "Detected OS: $os_type"

    validate_environment

    local docker_compose=$(get_docker_compose_cmd)
    print_success "Docker and Docker Compose are available"

    # Check host entry
    if check_host_entry; then
        print_success "invoiceshelf.test host entry already exists"
    else
        print_warning "invoiceshelf.test host entry not found"
        add_host_entry "$os_type"
    fi

    # Select database type
    local db_type=$(select_database)
    print_success "Selected database: $db_type"

    # Ask about Gotenberg
    local use_gotenberg=$(ask_gotenberg)

    # Build compose file name
    local compose_file
    if [ "$use_gotenberg" = "yes" ]; then
        compose_file="docker/development/docker-compose.${db_type}.gotenberg.yml"
        print_success "Using Gotenberg-enabled compose file"
    else
        compose_file="docker/development/docker-compose.${db_type}.yml"
        print_success "Using standard compose file"
    fi

    # Check if compose file exists
    if [ ! -f "$compose_file" ]; then
        print_error "Compose file not found: $compose_file"
        exit 1
    fi

    # Save configuration for future use
    save_config "$compose_file"

    print_info "Starting development environment..."
    print_info "Compose file: $compose_file"

    # Start the development environment
    if $docker_compose -f "$compose_file" up -d; then
        echo ""
        print_success "Development environment started successfully!"
        show_service_info
    else
        print_error "Failed to start development environment"
        exit 1
    fi
}

# Main script execution
main() {
    local command=${1:-""}

    case "$command" in
        "start")
            validate_environment > /dev/null
            cmd_start
            ;;
        "stop")
            validate_environment > /dev/null
            cmd_stop
            ;;
        "destroy")
            validate_environment > /dev/null
            cmd_destroy
            ;;
        "logs")
            validate_environment > /dev/null
            cmd_logs "$@"
            ;;
        "rebuild")
            validate_environment > /dev/null
            cmd_rebuild
            ;;
        "shell")
            validate_environment > /dev/null
            cmd_shell
            ;;
        "run")
            validate_environment > /dev/null
            cmd_run "$@"
            ;;
        "test")
            validate_environment > /dev/null
            cmd_test "$@"
            ;;
        "format")
            validate_environment > /dev/null
            cmd_format "$@"
            ;;
        "help"|"-h"|"--help")
            show_usage
            ;;
        "")
            setup_environment
            ;;
        *)
            print_error "Unknown command: $command"
            echo ""
            show_usage
            exit 1
            ;;
    esac
}

# Run main function
main "$@"
