#!/bin/bash

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

set -euo pipefail

# Script to run Rust examples from README.md and examples/rust/README.md files
# Usage: ./scripts/run-rust-examples-from-readme.sh [TARGET]
#
# TARGET - Optional target architecture (e.g., x86_64-unknown-linux-musl)
#          If not provided, uses the default target
#
# This script will run all the commands from both README.md and examples/rust/README.md files
# and check if they pass or fail.
# If any command fails, it will print the command and exit with non-zero status.
# If all commands pass, it will remove the log file and exit with zero status.
#
# Note: This script assumes that the iggy-server is not running and will start it in the background.
#       It will wait until the server is started before running the commands.
#       It will also terminate the server after running all the commands.
#       Script executes every command in README files which is enclosed in backticks (`) and starts
#       with `cargo r --bin iggy -- ` or `cargo run --example`. Other commands are ignored.
#       Order of commands in README files is important as script will execute them from top to bottom.
#

readonly LOG_FILE="iggy-server.log"
readonly PID_FILE="iggy-server.pid"
readonly TIMEOUT=300

# Get target architecture from argument or use default
TARGET="${1:-}"
if [ -n "${TARGET}" ]; then
    echo "Using target architecture: ${TARGET}"
else
    echo "Using default target architecture"
fi

# Remove old server data if present
test -d local_data && rm -fr local_data
test -e ${LOG_FILE} && rm ${LOG_FILE}
test -e ${PID_FILE} && rm ${PID_FILE}

# Check if server binary exists
SERVER_BIN=""
if [ -n "${TARGET}" ]; then
    SERVER_BIN="target/${TARGET}/debug/iggy-server"
else
    SERVER_BIN="target/debug/iggy-server"
fi

if [ ! -f "${SERVER_BIN}" ]; then
    echo "Error: Server binary not found at ${SERVER_BIN}"
    echo "Please build the server binary before running this script:"
    if [ -n "${TARGET}" ]; then
        echo "  cargo build --target ${TARGET} --bin iggy-server"
    else
        echo "  cargo build --bin iggy-server"
    fi
    exit 1
fi

echo "Using server binary at ${SERVER_BIN}"

# Check that CLI and examples are built
CLI_BIN=""
if [ -n "${TARGET}" ]; then
    CLI_BIN="target/${TARGET}/debug/iggy"
else
    CLI_BIN="target/debug/iggy"
fi

if [ ! -f "${CLI_BIN}" ]; then
    echo "Error: CLI binary not found at ${CLI_BIN}"
    echo "Please build the CLI and examples before running this script:"
    if [ -n "${TARGET}" ]; then
        echo "  cargo build --target ${TARGET} --bin iggy --examples"
    else
        echo "  cargo build --bin iggy --examples"
    fi
    exit 1
fi

echo "Using CLI binary at ${CLI_BIN}"

# Run iggy server using the prebuilt binary
echo "Starting server from ${SERVER_BIN}..."
IGGY_ROOT_USERNAME=iggy IGGY_ROOT_PASSWORD=iggy ${SERVER_BIN} &>${LOG_FILE} &
echo $! >${PID_FILE}

# Wait until "Iggy server has started" string is present inside iggy-server.log
SERVER_START_TIME=0
while ! grep -q "Iggy server has started" ${LOG_FILE}; do
    if [ ${SERVER_START_TIME} -gt ${TIMEOUT} ]; then
        echo "Server did not start within ${TIMEOUT} seconds."
        ps fx
        cat ${LOG_FILE}
        exit 1
    fi
    echo "Waiting for Iggy server to start... ${SERVER_START_TIME}"
    sleep 1
    ((SERVER_START_TIME += 1))
done

# Execute all matching CLI commands from README.md and check if they pass or fail
while IFS= read -r command; do
    # Remove backticks from command
    command=$(echo "${command}" | tr -d '`')
    # Add target flag if specified
    if [ -n "${TARGET}" ]; then
        command=$(echo "${command}" | sed "s/cargo r /cargo r --target ${TARGET} /g" | sed "s/cargo run /cargo run --target ${TARGET} /g")
    fi
    echo -e "\e[33mChecking CLI command:\e[0m ${command}"
    echo ""

    set +e
    eval "${command}"
    exit_code=$?
    set -e

    # Stop at first failure
    if [ ${exit_code} -ne 0 ]; then
        echo ""
        echo -e "\e[31mCLI command failed:\e[0m ${command}"
        echo ""
        break
    fi

done < <(grep -E "^\`cargo r --bin iggy -- " README.md)

# Execute all example commands from README.md and examples/rust/README.md and check if they pass or fail
for readme_file in README.md examples/rust/README.md; do
    if [ ! -f "${readme_file}" ]; then
        continue
    fi

    while IFS= read -r command; do
        # Remove backticks and comments from command
        command=$(echo "${command}" | tr -d '`' | sed 's/^#.*//')
        # Skip empty lines
        if [ -z "${command}" ]; then
            continue
        fi
        # Add target flag if specified
        if [ -n "${TARGET}" ]; then
            command="${command//cargo run /cargo run --target ${TARGET} }"
        fi
        echo -e "\e[33mChecking example command from ${readme_file}:\e[0m ${command}"
        echo ""

        set +e
        eval "${command}"
        exit_code=$?
        set -e

        # Stop at first failure
        if [ ${exit_code} -ne 0 ]; then
            echo ""
            echo -e "\e[31mExample command failed:\e[0m ${command}"
            echo ""
            break 2 # Break from both loops
        fi
        # Add a small delay between examples to avoid potential race conditions
        sleep 2

    done < <(grep -E "^cargo run --example" "${readme_file}")
done

# Terminate server
kill -TERM "$(cat ${PID_FILE})"
test -e ${PID_FILE} && rm ${PID_FILE}

# If everything is ok remove log and pid files otherwise cat server log
if [ "${exit_code}" -eq 0 ]; then
    echo "Test passed"
else
    echo "Test failed, see log file:"
    test -e ${LOG_FILE} && cat ${LOG_FILE}
fi

test -e ${LOG_FILE} && rm ${LOG_FILE}
test -e ${PID_FILE} && rm ${PID_FILE}

exit "${exit_code}"
