#!/bin/bash
# Script to start/reset reset all websites. Assumes images are loaded into Docker (see `load_docker_imgs.sh`)
# For docker-based environments, containers are force removed and re-initialized (thus can use for reset too).

# Usage: (see below for more details)
# ./start_reset_envs.sh [-f] all classifieds shopping admin reddit gitlab wikipedia homepagevwa homepagewa
# -f: Run Flask server in the foreground
# If 'all' is in the list, start/reset all websites


#===============================================================================
# Custom Paths/URL/Ports.
#===============================================================================
#FIXME:  Modify this according to your needs
BASE_URL='localhost'                                      # To change must map endpoints in /etc/hosts. See `environment_docker.README.md`.
WIKIPEDIA_PATH='/data1/webgui/vwebarena/docker_imgs/'     # Dir where the .zim file to host the wikipedia website was saved.
                                                          # Note: `vwebarena` and `webarena` homepages are different since involve different websites.
CLASSIFIEDS_PATH='/data1/webgui/vwebarena/docker_imgs/classifieds_docker_compose'
HOMEPAGE_PATH_VWA='./environment_docker/vwebarena-homepage/'   # Dir where the files to render the homepage are saved.
HOMEPAGE_PATH_WA='./environment_docker/webarena-homepage/'   # Dir where the files to render the homepage are saved.

# Ports; these are usually available and don't require `sudo`; change as needed.
declare -A ports
ports=(
  ["shopping"]=7770
  ["admin"]=7780
  ["reddit"]=9999
  ["gitlab"]=8023
  ["classifieds"]=9980
  ["wikipedia"]=8888
  ["homepage"]=4399
)
# E.g. website: shopping will be available at "http://localhost:7770/"



#===============================================================================
# Auxiliary functions
#===============================================================================

# Check if a site is in the list of inputs
is_site_in_list() {
  local site="$1"
  for s in "${sites[@]}"; do
    if [[ "$s" == "$site" ]]; then
      return 0
    fi
  done
  return 1
}

# Update homepage index.html with custom ports and BASE_URL
update_html_template() {
  local template_file="$1"
  local output_file="$2"

  sed -e "s|<your-server-hostname>|$BASE_URL|g" \
      -e "s|<classifieds-port>|${ports["classifieds"]}|g" \
      -e "s|<shopping-port>|${ports["shopping"]}|g" \
      -e "s|<reddit-port>|${ports["reddit"]}|g" \
      -e "s|<wikipedia-port>|${ports["wikipedia"]}|g" \
      -e "s|<gitlab-port>|${ports["gitlab"]}|g" \
      -e "s|<admin-port>|${ports["admin"]}|g" \
      "$template_file" > "$output_file"
}

# Update classifieds docker-compose.yml with custom port and BASE_URL
update_docker_compose() {
  local port="$1"
  local url="$2"
  local template_file="$3"
  local output_file="$4"

  sed -e "s|<classifieds_port>|$port|g" -e "s|<your-server-hostname>|$url|g" "$template_file" > "$output_file"
}

# Check if a Docker container is running
container_running() {
  local container_name="$1"
  if docker ps --format '{{.Names}}' | grep -q "$container_name"; then
    return 0
  fi
  return 1
}

# Check if a Docker container exists 
container_exists() {
  local container_name="$1"
  if docker ps -a --format '{{.Names}}' | grep -qw "$container_name"; then
    return 0
  fi
  return 1
}

# Function to kill any active homepage process
kill_homepage_process() {
    if pgrep -f "python3 .*/app.py --port ${ports["homepage"]} --base-url $BASE_URL" > /dev/null; then
        echo "Killing any existing homepage Flask process..."
        pkill -f "python3 .*/app.py --port ${ports["homepage"]} --base-url $BASE_URL"
    fi
}

disable_shopping_indexing(){
    # Disable re-indexing of products in shopping website
    docker exec shopping /var/www/magento2/bin/magento indexer:set-mode schedule catalogrule_product
    docker exec shopping /var/www/magento2/bin/magento indexer:set-mode schedule catalogrule_rule
    docker exec shopping /var/www/magento2/bin/magento indexer:set-mode schedule catalogsearch_fulltext
    docker exec shopping /var/www/magento2/bin/magento indexer:set-mode schedule catalog_category_product
    docker exec shopping /var/www/magento2/bin/magento indexer:set-mode schedule customer_grid
    docker exec shopping /var/www/magento2/bin/magento indexer:set-mode schedule design_config_grid
    docker exec shopping /var/www/magento2/bin/magento indexer:set-mode schedule inventory
    docker exec shopping /var/www/magento2/bin/magento indexer:set-mode schedule catalog_product_category
    docker exec shopping /var/www/magento2/bin/magento indexer:set-mode schedule catalog_product_attribute
    docker exec shopping /var/www/magento2/bin/magento indexer:set-mode schedule catalog_product_price
    docker exec shopping /var/www/magento2/bin/magento indexer:set-mode schedule cataloginventory_stock
}

# Write custom URLs to file for later reference
URL_FILE="./config/webarena_urls/urls.txt"
> $URL_FILE
for site in "${!ports[@]}"; do
    echo "${site^^} http://$BASE_URL:${ports[$site]}" >> $URL_FILE
done

#===============================================================================
# User input
#===============================================================================

# Parse command line arguments, filling 'sites' array
foreground=false; while getopts "f" opt; do [ "$opt" = "f" ] && foreground=true; done
shift $((OPTIND -1)); sites=("$@")

# If 'all_vwa' is in the list, reset all VWebArena websites
if [[ " ${sites[@]} " =~ " all_vwa " ]]; then
    sites=("shopping" "classifieds" "reddit" "wikipedia" "homepagevwa")
    # print sites
    echo "Starting/resetting all websites: ${sites[@]}"
fi

# Print usage
if [ ${#sites[@]} -eq 0 ]; then
    echo "Usage: $0 [-f] <site1> <site2> ..."
    echo "  -f: Run Flask server in the foreground"
    echo "  <site1>, <site2>, ...: List of websites to start/reset. Options: shopping, admin, reddit, gitlab, classifieds, wikipedia, homepagewa, homepagevwa"
    exit 1
fi

# If both homepagewa and homepagevwa, print error
if [[ " ${sites[@]} " =~ " homepagewa " ]] && [[ " ${sites[@]} " =~ " homepagevwa " ]]; then
    echo "Error: both homepagewa and homepagevwa cannot be specified together."
    exit 1
fi

#===============================================================================
# Launch websites
#===============================================================================
# Write custom URLs to file for later reference
URL_FILE="./config/webarena_urls/urls.txt"
> $URL_FILE
for site in "${!ports[@]}"; do
    echo "${site^^} http://$BASE_URL:${ports[$site]}" >> $URL_FILE
done

# Launch Social Forum Website (Reddit) [WebArena & VWebArena]
if is_site_in_list "reddit"; then
    if container_exists "forum"; then
        echo "Removing existing forum container..."
        docker rm -f forum
    fi
    docker run --name forum -p ${ports["reddit"]}:80 -d postmill-populated-exposed-withimg
    
    # # If reddit is the only site in list, wait longer for services to start
    # if [ ${#sites[@]} -eq 1 ] && [ "${sites[0]}" == "reddit" ]; then
    #     echo "Waiting for reddit to start..."
    #     sleep 30
    # fi
fi

# Launch Shopping Website (OneStopShop) [WebArena & VWebArena]
if is_site_in_list "shopping"; then
    if container_exists "shopping"; then
        echo "Removing existing shopping container..."
        docker rm -f shopping
    fi

    docker run --name shopping -p ${ports["shopping"]}:80 -d shopping_final_0712    # 7770: port for local machine; 80: port in Docker container
    echo "Starting services..."
    sleep 10 # wait a bit for services to start
    docker exec shopping /var/www/magento2/bin/magento setup:store-config:set --base-url="http://$BASE_URL:${ports["shopping"]}"
    docker exec shopping mysql -u magentouser -pMyPassword magentodb -e  "UPDATE core_config_data SET value='http://$BASE_URL:${ports["shopping"]}/' WHERE path = 'web/secure/base_url';"
    docker exec shopping /var/www/magento2/bin/magento cache:flush

    # Disable re-indexing of products
    disable_shopping_indexing
fi

# Launch Shopping Admin Website (E-commerce Content Management System (CMS)) [WebArena]
if is_site_in_list "admin"; then
    if container_exists "shopping_admin"; then
        echo "Removing existing admin container..."
        docker rm -f shopping_admin
    fi
    docker run --name shopping_admin -p ${ports["admin"]}:80 -d shopping_admin_final_0719
    docker exec shopping_admin /var/www/magento2/bin/magento setup:store-config:set --base-url="http://$BASE_URL:${ports["admin"]}"
    docker exec shopping_admin mysql -u magentouser -pMyPassword magentodb -e "UPDATE core_config_data SET value='http://$BASE_URL:${ports["admin"]}/' WHERE path = 'web/secure/base_url';"
    docker exec shopping_admin /var/www/magento2/bin/magento cache:flush
fi


# Launch Gitlab Website [WebArena]
if is_site_in_list "gitlab"; then
    if container_exists "gitlab"; then
        echo "Removing existing gitlab container..."
        docker rm -f gitlab
    fi
    docker run --name gitlab -d -p ${ports["gitlab"]}:${ports["gitlab"]} gitlab-populated-final-port8023 /opt/gitlab/embedded/bin/runsvdir-start
    docker exec gitlab sed -i "s|^external_url.*|external_url 'http://$BASE_URL:${ports["gitlab"]}'|" /etc/gitlab/gitlab.rb
    docker exec gitlab gitlab-ctl reconfigure
fi

# Launch classifieds website [VWebArena]
if is_site_in_list "classifieds"; then
    if container_exists "classifieds"; then
        echo "Removing existing classifieds container..."
        docker rm -f classifieds
    fi
    if container_exists "classifieds_db"; then
        docker rm -f classifieds_db
    fi

    update_docker_compose "${ports["classifieds"]}" "$BASE_URL" "$CLASSIFIEDS_PATH/docker-compose-raw.yml" "$CLASSIFIEDS_PATH/docker-compose.yml"

    # If you didn't pull the image, docker-compose will download and take a lot of time; recommended to download first. See Readme.
    docker compose -f "$CLASSIFIEDS_PATH/docker-compose.yml" up --build -d
    echo "Starting services..."

    # Loop until the database is ready to accept the password
    until docker exec classifieds_db mysql -u root -ppassword -e "SELECT 1" &> /dev/null; do
        echo "Waiting for database connection..."
        sleep 5
    done
    echo "Populating database..." 
    docker exec classifieds_db mysql -u root -ppassword osclass -e 'source docker-entrypoint-initdb.d/osclass_craigslist.sql'
fi

# Launch Wikipedia website [WebArena & VWebArena]
if is_site_in_list "wikipedia"; then
    if container_exists "wikipedia"; then
        echo "Removing existing wikipedia container..."
        docker rm -f wikipedia
    fi
    docker run -d --name=wikipedia --volume="$WIKIPEDIA_PATH/:/data" -p ${ports["wikipedia"]}:80 ghcr.io/kiwix/kiwix-serve:3.3.0 wikipedia_en_all_maxi_2022-05.zim
    # Example URL: http://localhost:8888/wikipedia_en_all_maxi_2022-05/A/User:The_other_Kiwix_guy/Landing
fi


# Launch Homepage [WebArena & VWebArena]
if is_site_in_list "homepagewa" || is_site_in_list "homepagevwa"; then
    # Kill any active homepage process
    kill_homepage_process

    if is_site_in_list "homepagewa"; then
        HOMEPAGE_PATH="$HOMEPAGE_PATH_WA"
    else
        HOMEPAGE_PATH="$HOMEPAGE_PATH_VWA"
    fi

    # replace placeholder <your-server-hostname> with the basename for websites in the HTML file to render the homepage
    update_html_template "$HOMEPAGE_PATH/templates/index_raw.html" "$HOMEPAGE_PATH/templates/index.html"

    if $foreground; then
        # Run Flask in the foreground; binds to the terminal running the script
        python3 $HOMEPAGE_PATH/app.py --port ${ports["homepage"]} --base-url $BASE_URL
    else
        # Run Flask in the background
        nohup python3 $HOMEPAGE_PATH/app.py --port ${ports["homepage"]} --base-url $BASE_URL > $HOMEPAGE_PATH/flask.log 2>&1 &
        sleep 2
        echo "Flask running on the background. Process ID: $(ps aux | grep '[p]ython3' | grep "$HOMEPAGE_PATH/app.py" | awk '{print $2}')"
    fi
fi



# If not homepagewa or homepagevwa, print running containers
if ! is_site_in_list "homepagewa" && ! is_site_in_list "homepagevwa"; then
    echo -e "\nRunning containers:"
    docker ps
fi

# Print reachability status of websites
# if ! $foreground; then
#     echo "Waiting for services to start..."
#     sleep 5
#     echo "Checking websites status..."
#     echo -e "\nWEBSITES STATUS" 
#     ./scripts/environments/check_websites.sh
# fi



# Wait for websites to be up
if ! $foreground; then
    echo "Looping until ${sites[@]} are up..."
    max_attempts=30  # Maximum number of attempts (5 minutes with 10s sleep)
    attempt=1
    
    while [ $attempt -le $max_attempts ]; do
        echo -e "\nAttempt $attempt/$max_attempts:"
        # Store the check_websites.sh output in a temporary file
        ./scripts/environments/check_websites.sh > temp_status.txt
        echo "$(cat temp_status.txt)"
        
        all_sites_up=true
        for site in "${sites[@]}"; do
            # Skip homepage checks since they're handled differently
            if [[ "$site" == "homepagewa" ]] || [[ "$site" == "homepagevwa" ]]; then
                continue
            fi
            # Convert site name to uppercase for matching
            site_upper=$(echo "$site" | tr '[:lower:]' '[:upper:]')
            if ! grep -q "^$site_upper.*UP" temp_status.txt; then
                all_sites_up=false
                break
            fi
        done
        
        rm temp_status.txt
        
        if $all_sites_up; then
            echo "All requested services are up!"
            break
        fi
        
        if [ $attempt -eq $max_attempts ]; then
            echo "Warning: Some services failed to start after $max_attempts attempts"
            echo -e "\nFinal websites status:"
            ./scripts/environments/check_websites.sh
            break
        fi
        wait_for=5
        echo "Waiting for $wait_for seconds before next attempt..."
        sleep $wait_for
        ((attempt++))
    done
fi