#!/bin/bash

set -o nounset
set -o errexit
set -o pipefail

EML_DIR="/opt/tests/eml"
SMTP_HOST="127.0.0.1"
SMTP_SOURCE_PROG="/usr/local/bin/smtp-source.py"

SCRIPT_PATH="$(readlink -f "$0")"
SCRIPT_DIR="${SCRIPT_PATH%/*}"

declare -a SEARCH_QUERIES
declare -a SEARCH_HITS
declare -A SHA256_SUM

VERDICT=0
RESULT_CRITICAL=2

error() {
   echo "$@"
   exit 1
}

set_verdict() {
   [[ ${VERDICT} -ge "$1" ]] || { VERDICT="$1"; echo "verdict: ${VERDICT}"; }
}

get_verdict() {
   echo "verdict: ${VERDICT}"
   exit "$VERDICT"
}

count_status_values() {
   local logfile="mail.log"

   echo "${FUNCNAME[0]}"

   # shellcheck disable=SC2153
   docker exec "$CONTAINER" cat "/var/log/${logfile}" > "$logfile"

   received=$(grep -c "received:" "$logfile")
   stored=$(grep -c "status=stored" "$logfile")
   discarded=$(grep -c "status=discarded" "$logfile") || true
   duplicate=$(grep -c "status=duplicate" "$logfile") || true

   [[ $received -eq $1 ]] || set_verdict $RESULT_CRITICAL
   [[ $stored -eq $2 ]] || set_verdict $RESULT_CRITICAL
   [[ $discarded -eq $3 ]] || set_verdict $RESULT_CRITICAL
   [[ $duplicate -eq $4 ]] || set_verdict $RESULT_CRITICAL
}

append_query() {
   SEARCH_QUERIES+=( "$1" )
   SEARCH_HITS+=( "$2" )
}

append_queries() {
   local index="main1,dailydelta1,delta1"

   if [[ $RT -eq 1 ]]; then index="piler1"; fi

   append_query "select * from ${index} WHERE MATCH('@subject budaörsi dc felmérés')" 9
   append_query "select * from ${index} WHERE MATCH('@sender gruppi.hu')" 4
   append_query "select * from ${index} WHERE attachments > 0 AND MATCH('@subject spam  ')" 85
   append_query "select * from ${index} WHERE attachments > 0 AND MATCH('@subject spam @attachment_types image')" 15
   append_query "select * from ${index} WHERE MATCH('@(subject,body)  New Task TSK002*')" 29
   append_query "select * from ${index} WHERE MATCH('@subject \"virtualfax daily summary\" | \"adsl hibajegy\"')" 11
}

run_sphinx_tests() {
   echo "${FUNCNAME[0]}"

   append_queries

   for i in $(seq 0 $((${#SEARCH_QUERIES[@]}-1)) )
   do
      hits=$( echo "${SEARCH_QUERIES[$i]}; show meta" | docker exec -i "$CONTAINER" mysql -h manticore -P9306 | grep total_found|awk '{ print $2 }' )
      echo "${hits} ${SEARCH_HITS[$i]}"
   done
}

run_import_job() {
   echo "${FUNCNAME[0]}"
   docker exec "$CONTAINER" su piler -c /usr/libexec/piler/import.sh
}

wait_until_emails_are_processed() {
   local container="$1"
   local num=$2
   local loops
   local i=0
   local processed=0

   echo "${FUNCNAME[0]}"

   loops=$(( num / 100 ))

   while true; do
      processed="$(docker exec "$container" grep -c status= /var/log/mail.log)"
      i=$(( i + 1 ))
      echo "processed ${processed} messages"

      [[ $processed -lt "$num" ]] || break

      sleep 10

      [[ $i -gt $loops ]] && error "${container} did not process ${num} emails"
   done

   echo "${processed} emails are processed in ${container}"
}

read_eml_files_data() {
   local fname
   local message_id
   local sum
   local ts_start
   local ts_stop
   local sumsfile="/opt/tests/shasums.txt"

   ts_start="$(date +%s)"

   if [[ -f "$sumsfile" ]]; then
      echo "reading ${sumsfile}"
      # shellcheck disable=SC1090
      source "$sumsfile"
   else
      echo "reading eml files from ${EML_DIR}"

      while read -r -d $'\0' fname; do
         if [[ $(grep -c -i Message-ID: "$fname") -gt 0 ]]; then
            message_id="$(grep -i ^Message-ID: "$fname" | head -1 | awk '{ print $2 }')"
            if [[ "$message_id" ]]; then
               sum="$(sha256sum "$fname" | cut -f1 -d ' ')"
               SHA256_SUM["$message_id"]="$sum"
            fi
         fi
      done < <(find "$EML_DIR" -type f -print0)
   fi

   ts_stop="$(date +%s)"
   echo "${FUNCNAME[0]}" "took" $(( ts_stop - ts_start )) "secs"
}

test_retrieved_messages_are_the_same() {
   local container="$1"
   local database="$2"
   local message_id
   local i=0
   local bad=0
   declare -A PILER_MESSAGE_ID
   declare -a RETRIEVED_SHA256_SUM

   shift
   shift

   echo "${FUNCNAME[0]}" "$container" "$database"

   while read -r message_id retrieved_cksum; do
      #echo "digest=$retrieved_cksum" "mid=$message_id"

      PILER_MESSAGE_ID["$retrieved_cksum"]="$message_id"
      RETRIEVED_SHA256_SUM+=( "$retrieved_cksum" )
   done < <(docker exec -i "$CONTAINER" mysql -u piler -ppiler123 -h mysql --skip-column-names "$database" <<< "select message_id, digest from metadata where digest != ''" 2>/dev/null)

   for retrieved_cksum in "${RETRIEVED_SHA256_SUM[@]}"; do
      message_id="${PILER_MESSAGE_ID["$retrieved_cksum"]}"
      i=$(( i + 1 ))
      # some of the messages are NOT present in the metadata table
      # either because of a rule discarded it, or it has a nested
      # mime message inside which overrides the first Message-ID
      # found by a naive grep in read_eml_files_data()
      if [[ ${SHA256_SUM["$message_id"]+abc} ]]; then
         [[ "$retrieved_cksum" == "${SHA256_SUM["$message_id"]}" ]] || { bad=$(( bad + 1 )); echo "$message_id" is BAD; }
      fi
   done

   if [[ $bad -gt 0 ]]; then
      set_verdict "$RESULT_CRITICAL"
      exit 1
   fi

   echo "tested ${i} messages"
}

purge_300_emails() {
   local container="$1"
   local manticore_host="$2"
   local piler_id
   local found

   echo "${FUNCNAME[0]}"

   piler_id="$(docker exec -i "$container" mysql --defaults-file=/etc/piler/.my.cnf -N piler <<< "select piler_id from metadata where id=1" 2>/dev/null)"

   echo "piler id: ${piler_id}"

   found=$(docker exec -i "$container" find "/var/piler/store/00/" -name "${piler_id}.m" 2>/dev/null | wc -l)
   [[ $found -eq 1 ]] || set_verdict $RESULT_CRITICAL

   echo "Purging emails"

   docker exec -i "$container" mysql --defaults-file=/etc/piler/.my.cnf piler <<< "update metadata set retained=1000000 where id<=300" 2>/dev/null
   docker exec "$container" su piler -c "/usr/libexec/piler/purge.sh" 2>/dev/null

   echo "Test if emails are purge from manticore"

   if [[ $(docker exec -i "$container" mysql -N -h "$manticore_host" -P9306 <<< "select count(*) as count from piler1 where id<=300") -gt 0 ]]; then
      echo "Purge has not removed all messages from 1-300"
      docker exec -i "$container" mysql -N -h "$manticore_host" -P9306 <<< "select count(*) as count from piler1 where id<=300"
      set_verdict $RESULT_CRITICAL
   fi

   echo "Test if ${piler_id} still exists"

   found=$(docker exec -i "$container" find "/var/piler/store/00" -name "${piler_id}.m" 2>/dev/null | wc -l)
   if [[ $found -gt 0 ]]; then
      echo "Still found ${found} messages that supposed to be deleted"
      set_verdict $RESULT_CRITICAL
   fi
}


for i in Inbox Inbox2 Levelszemet Levelszemet2 spam0 spam1 spam2 journal deduptest special; do
   "$SMTP_SOURCE_PROG" -s "$SMTP_HOST" -r "archive@${ARCHIVE_HOST}" -p 25 -t 20 --dir "$EML_DIR/$i" --no-counter
done

"$SMTP_SOURCE_PROG" -s "$SMTP_HOST" -r "archive@${ARCHIVE_HOST}" extra@addr.ess another@extra.addr -p 25 -t 20 --dir "$EML_DIR/virus" --no-counter

wait_until_emails_are_processed "$CONTAINER" 3020

[[ $RT -eq 1 ]] || docker exec "$CONTAINER" su piler -c /usr/libexec/piler/indexer.delta.sh 2>/dev/null

count_status_values 3020 2909 111 0

read_eml_files_data
test_retrieved_messages_are_the_same "$CONTAINER" "piler"

run_sphinx_tests

docker exec "$CONTAINER" su piler -c 'php /usr/libexec/piler/generate_stats.php --webui /var/piler/www --start=2015/01/01 --stop=2021/12/31'

docker exec "$CONTAINER" su piler -c 'php /usr/libexec/piler/sign.php --webui /var/piler/www --mode time'

run_import_job

purge_300_emails "$CONTAINER" "manticore"

docker exec "$CONTAINER" tail -30 /var/log/nginx/error.log

docker exec -i "$CONTAINER" bash -c 'cat >>/root/.bashrc' <<< "alias n='tail -f /var/log/nginx/error.log'"
docker exec -i "$CONTAINER" bash -c 'cat >>/root/.bashrc' <<< "alias t='tail -f /var/log/mail.log'"

pushd "$SCRIPT_DIR"
docker cp addons.sh "${CONTAINER}:/tmp"
popd

get_verdict
