#!/usr/bin/env bash
# Docker: Rebuild E2E Environment - Execution Script
#
# Rebuilds the Docker image and restarts the Playwright E2E testing
# environment with fresh code and optionally clean state.

set -euo pipefail

# Source helper scripts
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SKILLS_SCRIPTS_DIR="$(cd "${SCRIPT_DIR}/../scripts" && pwd)"

# shellcheck source=../scripts/_logging_helpers.sh
source "${SKILLS_SCRIPTS_DIR}/_logging_helpers.sh"
# shellcheck source=../scripts/_error_handling_helpers.sh
source "${SKILLS_SCRIPTS_DIR}/_error_handling_helpers.sh"
# shellcheck source=../scripts/_environment_helpers.sh
source "${SKILLS_SCRIPTS_DIR}/_environment_helpers.sh"

# Project root is 3 levels up from this script
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"

# Docker compose file for Playwright E2E tests
COMPOSE_FILE=".docker/compose/docker-compose.playwright-local.yml"
CONTAINER_NAME="charon-e2e"
IMAGE_NAME="charon:local"
HEALTH_TIMEOUT=60
HEALTH_INTERVAL=5

# Default parameter values
NO_CACHE=false
CLEAN=false
PROFILE=""

# Parse command-line arguments
parse_arguments() {
    while [[ $# -gt 0 ]]; do
        case "$1" in
            --no-cache)
                NO_CACHE=true
                shift
                ;;
            --clean)
                CLEAN=true
                shift
                ;;
            --profile=*)
                PROFILE="${1#*=}"
                shift
                ;;
            --profile)
                PROFILE="${2:-}"
                shift 2
                ;;
            -h|--help)
                show_help
                exit 0
                ;;
            *)
                log_warning "Unknown argument: $1"
                shift
                ;;
        esac
    done
}

# Show help message
show_help() {
    cat << EOF
Usage: run.sh [OPTIONS]

Rebuild Docker image and restart E2E Playwright container.

Options:
    --no-cache          Force rebuild without Docker cache
    --clean             Remove test volumes for fresh state
    --profile=PROFILE   Docker Compose profile to enable
                        (security-tests, notification-tests)
    -h, --help          Show this help message

Environment Variables:
    DOCKER_NO_CACHE         Force rebuild without cache (default: false)
    SKIP_VOLUME_CLEANUP     Preserve test data volumes (default: false)

Examples:
    run.sh                              # Standard rebuild
    run.sh --no-cache                   # Force complete rebuild
    run.sh --clean                      # Rebuild with fresh volumes
    run.sh --profile=security-tests     # Enable CrowdSec for testing
    run.sh --no-cache --clean           # Complete fresh rebuild
EOF
}

# Stop existing containers
stop_containers() {
    log_step "STOP" "Stopping existing E2E containers"

    local compose_cmd="docker compose -f ${COMPOSE_FILE}"

    # Add profile if specified
    if [[ -n "${PROFILE}" ]]; then
        compose_cmd="${compose_cmd} --profile ${PROFILE}"
    fi

    # Stop and remove containers
    if ${compose_cmd} ps -q 2>/dev/null | grep -q .; then
        log_info "Stopping containers..."
        ${compose_cmd} down --remove-orphans || true
    else
        log_info "No running containers to stop"
    fi
}

# Clean volumes if requested
clean_volumes() {
    if [[ "${CLEAN}" != "true" ]]; then
        return 0
    fi

    if [[ "${SKIP_VOLUME_CLEANUP:-false}" == "true" ]]; then
        log_warning "Skipping volume cleanup (SKIP_VOLUME_CLEANUP=true)"
        return 0
    fi

    log_step "CLEAN" "Removing test volumes"

    local volumes=(
        "playwright_data"
        "playwright_caddy_data"
        "playwright_caddy_config"
        "playwright_crowdsec_data"
        "playwright_crowdsec_config"
    )

    for vol in "${volumes[@]}"; do
        # Try both prefixed and unprefixed volume names
        for prefix in "compose_" ""; do
            local full_name="${prefix}${vol}"
            if docker volume inspect "${full_name}" &>/dev/null; then
                log_info "Removing volume: ${full_name}"
                docker volume rm "${full_name}" || true
            fi
        done
    done

    log_success "Volumes cleaned"
}

# Build Docker image
build_image() {
    log_step "BUILD" "Building Docker image: ${IMAGE_NAME}"

    local build_args=("-t" "${IMAGE_NAME}" ".")

    if [[ "${NO_CACHE}" == "true" ]] || [[ "${DOCKER_NO_CACHE:-false}" == "true" ]]; then
        log_info "Building with --no-cache"
        build_args=("--no-cache" "${build_args[@]}")
    fi

    log_command "docker build ${build_args[*]}"

    if ! docker build "${build_args[@]}"; then
        error_exit "Docker build failed"
    fi

    log_success "Image built successfully: ${IMAGE_NAME}"
}

# Start containers
start_containers() {
    log_step "START" "Starting E2E containers"

    local compose_cmd="docker compose -f ${COMPOSE_FILE}"

    # Add profile if specified
    if [[ -n "${PROFILE}" ]]; then
        log_info "Enabling profile: ${PROFILE}"
        compose_cmd="${compose_cmd} --profile ${PROFILE}"
    fi

    log_command "${compose_cmd} up -d"

    if ! ${compose_cmd} up -d; then
        error_exit "Failed to start containers"
    fi

    log_success "Containers started"
}

# Wait for container health
wait_for_health() {
    log_step "HEALTH" "Waiting for container to be healthy"

    local elapsed=0
    local healthy=false

    while [[ ${elapsed} -lt ${HEALTH_TIMEOUT} ]]; do
        local health_status
        health_status=$(docker inspect --format='{{.State.Health.Status}}' "${CONTAINER_NAME}" 2>/dev/null || echo "unknown")

        case "${health_status}" in
            healthy)
                healthy=true
                break
                ;;
            unhealthy)
                log_error "Container is unhealthy"
                docker logs "${CONTAINER_NAME}" --tail 20
                error_exit "Container health check failed"
                ;;
            starting)
                log_info "Health status: starting (${elapsed}s/${HEALTH_TIMEOUT}s)"
                ;;
            *)
                log_info "Health status: ${health_status} (${elapsed}s/${HEALTH_TIMEOUT}s)"
                ;;
        esac

        sleep "${HEALTH_INTERVAL}"
        elapsed=$((elapsed + HEALTH_INTERVAL))
    done

    if [[ "${healthy}" != "true" ]]; then
        log_error "Container did not become healthy in ${HEALTH_TIMEOUT}s"
        docker logs "${CONTAINER_NAME}" --tail 50
        error_exit "Health check timeout"
    fi

    log_success "Container is healthy"
}

# Verify environment
verify_environment() {
    log_step "VERIFY" "Verifying E2E environment"

    # Check container is running
    if ! docker ps --filter "name=${CONTAINER_NAME}" --format "{{.Names}}" | grep -q "${CONTAINER_NAME}"; then
        error_exit "Container ${CONTAINER_NAME} is not running"
    fi

    # Test health endpoint
    log_info "Testing health endpoint..."
    if curl -sf http://localhost:8080/api/v1/health &>/dev/null; then
        log_success "Health endpoint responding"
    else
        log_warning "Health endpoint not responding (may need more time)"
    fi

    # Show container status
    log_info "Container status:"
    docker ps --filter "name=charon-playwright" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
}

# Show summary
show_summary() {
    log_step "SUMMARY" "E2E environment ready"

    echo ""
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    echo "  E2E Environment Ready"
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    echo ""
    echo "  Application URL:  http://localhost:8080"
    echo "  Health Check:     http://localhost:8080/api/v1/health"
    echo "  Container:        ${CONTAINER_NAME}"
    echo ""
    echo "  Run E2E tests:"
    echo "    .github/skills/scripts/skill-runner.sh test-e2e-playwright"
    echo ""
    echo "  Run in debug mode:"
    echo "    .github/skills/scripts/skill-runner.sh test-e2e-playwright-debug"
    echo ""
    echo "  View logs:"
    echo "    docker logs ${CONTAINER_NAME} -f"
    echo ""
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
}

# Main execution
main() {
    parse_arguments "$@"

    # Validate environment
    log_step "ENVIRONMENT" "Validating prerequisites"
    validate_docker_environment || error_exit "Docker is not available"
    check_command_exists "docker" "Docker is required"

    # Validate project structure
    log_step "VALIDATION" "Checking project structure"
    cd "${PROJECT_ROOT}"
    check_file_exists "Dockerfile" "Dockerfile is required"
    check_file_exists "${COMPOSE_FILE}" "Playwright compose file is required"

    # Log configuration
    log_step "CONFIG" "Rebuild configuration"
    log_info "No cache: ${NO_CACHE}"
    log_info "Clean volumes: ${CLEAN}"
    log_info "Profile: ${PROFILE:-<none>}"
    log_info "Compose file: ${COMPOSE_FILE}"

    # Execute rebuild steps
    stop_containers
    clean_volumes
    build_image
    start_containers
    wait_for_health
    verify_environment
    show_summary

    log_success "E2E environment rebuild complete"
}

# Run main with all arguments
main "$@"
