#!/bin/bash
# Set parameters

upgrade=false

USE_CN_MIRROR=true
new_version="1.0.1"
DownPath="http://dl.fogworks.io/maxio/online_stake/facmgr"



function log {
    echo "$(date +"%Y-%m-%d %H:%M:%S") - $1" | tee -a $LOG_FILE
}

while getopts "ukv:" opt; do
  case ${opt} in
    u )
      upgrade=true
      ;;
    v )
      new_version=$OPTARG
      ;;
    k )
      USE_CN_MIRROR=false
      ;;
    \?)
       log "Invalid option: $OPTARG" 1>&2
      exit 1
      ;;
    : )
      log "Invalid option: $OPTARG requires an argument" 1>&2
      exit 1
      ;;
  esac
done



if [ "$upgrade" = true ]; then
    log "########## Starting upgrade facmgr ##########"
else
    log "########## Starting installation facmgr ##########"
fi


docker_env_file_path="/etc/apt/docker_sources.env"
SERVICES="vault kes minio minio-token ipfs prox_mpd"

COMPOSE_DIR="/opt/facmgr/service"
COMPOSE_FILE_AUTO_ENCRYPT="$COMPOSE_DIR/docker-compose-vault.yml"


DownUrlPath="$DownPath/facmgr_$new_version.tar.bz2"

file="/etc/pam.d/common-session"
script_path="/opt/bin/operation_record.sh"
profile_path="/etc/profile"
log_dir="/var/log/operation"
HostIp=$(hostname -I | awk '{ for(i=1;i<=NF;i++) { if (! ($i ~ /^192\.168\./ || $i ~ /^10\./ || $i ~ /^172\.(1[6-9]|2[0-9]|3[01])\./ )) print $i } }')
HostName="${HostIp//./-}"
InstallPath="/opt"
InstallDir="$InstallPath/facmgr"
InstallPacketPath="$InstallPath/facmgr_$new_version.tar.bz2"
SERVICE_FILE_URL="/opt/facmgr/app/config/facmgr.service"
SERVICE_FILE_PATH="/etc/systemd/system/facmgr.service"
SERVICE_UPDATE_FILE_URL="/opt/facmgr/app/config/facmgr_update.service"
SERVICE_UPDATE_SCRIPT_URL="/opt/facmgr/app/config/update_script.sh"
SERVICE_UPDATE_FILE_PATH="/etc/systemd/system/facmgr_update.service"

CN_DOCKER_HUB_REPO="maxio2-registry.cn-hangzhou.cr.aliyuncs.com"
DEFAULT_DOCKER_HUB_REPO="docker.io"
DOCKER_HUB_REPO_LIST=("$CN_DOCKER_HUB_REPO" "$DEFAULT_DOCKER_HUB_REPO")


LOG_DIR="/var/log/facmgr"
DataDIR="/data"
FACMGR_DIR="$DataDIR/facmgr"
FACMGR_DB="$DataDIR/facmgr/sqlite3.db"
FACMGR_LOG="$DataDIR/facmgr/log"
BACKUP_DIR="$DataDIR/facmgr/backup"
LOG_FILE="$LOG_DIR/facmgr_install.log"
DIRS=("$DataDIR" "$LOG_DIR" "$FACMGR_DIR" "$FACMGR_LOG" "$BACKUP_DIR")
limits_conf="/etc/security/limits.conf"
config_lines=(
    "* soft nofile 65535"
    "* hard nofile 65535"
    "root soft nofile 65535"
    "root hard nofile 65535"
)

source_path="/opt/facmgr_install/docker-compose-vault.yml"
source_path_temp="/opt/facmgr_install/temp/docker-compose-vault.yml"
source_path_cn="/opt/facmgr_install/docker-compose-vault_cn.yml"
source_path_cn_temp="/opt/facmgr_install/temp/docker-compose-vault_cn.yml"
destination_path="/opt/facmgr/service/"

create_log() {

  if [ ! -f "$LOG_FILE" ]; then
    mkdir -p "$LOG_DIR"
    touch "$LOG_FILE"
  fi

}



check_root() {
  if [[ $EUID -ne 0 ]]; then
    log "This script must be run as root"
    exit 1
  fi
}


create_directory() {
  local dir="$1"
  if [ ! -d "$dir" ]; then
    log "Directory $dir does not exist. Creating..."
    mkdir -p "$dir" || {
      log "Failed to create directory $dir"
      exit 1
    }
  fi
}

function check_domain_accessibility {
    local domain="$1"
    local max_retries="$2"

    for ((i = 1; i <= max_retries; i++)); do
        ping -c 1 "$domain" >/dev/null 2>&1
        if [ $? -eq 0 ]; then
            log "Domain $domain is accessible."
            return 0
        else
            log "Attempt $i: Domain $domain is not accessible."
        fi
    done

    log "Failed to access domain $domain after $max_retries attempts."
    exit 1
}

update_dns() {
# Set DNS server
  echo "nameserver 8.8.8.8" > /etc/resolv.conf
  if [ ! -f "/etc/resolv.conf" ]; then
    echo "nameserver 8.8.4.4" > /etc/resolv.conf
  elif ! grep -q "nameserver 8.8.4.4" /etc/resolv.conf; then
    echo "nameserver 8.8.4.4" >> /etc/resolv.conf
  fi

}


add_limit(){

if [ -f "$limits_conf" ]; then
    for line in "${config_lines[@]}"; do
        if grep -q "^$line" "$limits_conf"; then
            echo "The configuration '$line' already exists and does not need to be modified"
        else
            echo "$line" | tee -a "$limits_conf"
        fi
    done
else
    for line in "${config_lines[@]}"; do
        echo "$line" | tee -a "$limits_conf"
    done

fi

if ! grep -q "session required pam_limits.so" "$file"; then
    echo "session required pam_limits.so" >> "$file"
fi

}










update_compose() {


        if [ -f "/var/lib/facmgr/db/facmgr.db" ]; then
          result=$(sqlite3 /var/lib/facmgr/db/facmgr.db "select use_cn_mirror from service;")

          svc_result=$(sqlite3 /var/lib/facmgr/db/facmgr.db "select svc_state from service;")

          log "svc result is $svc_result, use_cn_mirror is $result" 

          if [ -f "$docker_env_file_path" ] && [ -s "$docker_env_file_path" ]; then
            OLD_DOCKER_HUB_REPO=$(grep '^DOCKER_HUB_REPO=' "$docker_env_file_path" | cut -d'=' -f2)

            if [[ " ${DOCKER_HUB_REPO_LIST[@]} " =~ " ${OLD_DOCKER_HUB_REPO} " ]]; then
              log "DOCKER_HUB_REPO is in the DOCKER_HUB_REPO_LIST."
            else
              log "DOCKER_HUB_REPO is not in the DOCKER_HUB_REPO_LIST."
              rm "$docker_env_file_path"
              echo "$CN_DOCKER_HUB_REPO" > "$docker_env_file_path"
            fi
          else
            log "File $docker_env_file_path does not exist or is empty."
          fi

          if [ -f "$docker_env_file_path" ] && [ -s "$docker_env_file_path" ]; then
            NEW_DOCKER_HUB_REPO=$(grep '^DOCKER_HUB_REPO=' "$docker_env_file_path" | cut -d'=' -f2)
          fi

          if [ "$svc_result" = "finish" ] && [ "$result" = 0 ]; then
            cp "$source_path_temp" "$destination_path"
            log "$source_path File copied successfully."
            sed -i "s/\${DOCKER_HUB_REPO}/$DEFAULT_DOCKER_HUB_REPO/g" "$destination_path/docker-compose-vault.yml"
          else
            cp "$source_path_cn_temp" "$destination_path/docker-compose-vault.yml"
            log "$source_path_cn File copied successfully."
            if [ -n "$NEW_DOCKER_HUB_REPO" ]; then
              sed -i "s/\${DOCKER_HUB_REPO}/$NEW_DOCKER_HUB_REPO/g" "$destination_path/docker-compose-vault.yml"
            else
              sed -i "s/\${DOCKER_HUB_REPO}/$CN_DOCKER_HUB_REPO/g" "$destination_path/docker-compose-vault.yml"
            fi
          fi


        else
          cp "$source_path_temp" "$destination_path"
          log "$source_path File copied successfully."
          sed -i "s/\${DOCKER_HUB_REPO}/$DEFAULT_DOCKER_HUB_REPO/g" "$destination_path/docker-compose-vault.yml"
        fi


        env_file="/opt/facmgr_install/.env"
        target_dir="/opt/facmgr/service"

        if [ ! -f "$target_dir/.env" ] && [ -f "$env_file" ]; then
            cp "$env_file" "$target_dir/.env"
            log "Environment file copied to $target_dir/.env." 
        fi


}


facmgr_install() {
  #if [ "$upgrade" != true ]; then
  #  if [ -e $InstallPacketPath ]; then
  #    rm $InstallPacketPath
  #    log "Old Packet removed."
  #  fi
      
  #fi
  download=false

  local cron_upgrade_file="/opt/.cron_upgrade"
  if [ ! -f "$cron_upgrade_file" ]; then
    if [ -f "$InstallPacketPath" ]; then
      # Calculate MD5 for both existing and downloaded files
      existing_md5=$(md5sum "$InstallPacketPath" | cut -d' ' -f1)
      #downloaded_md5=$(wget -qO- "$DownUrlPath" | md5sum | cut -d' ' -f1)
      remote_md5=$(curl -s "$DownPath/facmgr_${new_version}_md5" | awk '{print $1}')
    
      log "Existing MD5: $existing_md5, Remote MD5: $remote_md5"
      # Compare the MD5 sums
      if [ "$existing_md5" = "$remote_md5" ]; then
        log "File already exists and has the same MD5. No need to download."
      else
        rm -rf $InstallPacketPath
        # Download the new file
        wget "$DownUrlPath" -P "$InstallPath"
        log "New file downloaded."
        download=true
      fi
    else
      # Download the file if it doesn't exist
      wget "$DownUrlPath" -P "$InstallPath"
      log "File downloaded."
      download=true
    fi
  else
    log "$cron_upgrade_file already exists"
    FILE_PATH="/opt/.upgrade_file/upgrade_file.yaml"
    if [ -f "$FILE_PATH" ]; then
      UPGRADE_FLAG=$(grep -A 1 "facmgr:" "$FILE_PATH" | grep "upgrade:" | awk '{print $2}')
      log "facmgr UPGRADE_FLAG is $UPGRADE_FLAG"
      if [ "$UPGRADE_FLAG" == "true" ]; then
          download=true
      fi
    fi
  fi


  if [ "$download" = true ]; then
    if [ -d $InstallDir ]; then
      rm -r $InstallDir
      log "Old Packet dir removed."
    fi
  fi

  if [ ! -d $InstallDir ]; then
      # Unzip the new file
      tar -xf $InstallPacketPath -C $InstallPath
      log "New file unzipped."
      chmod +x $InstallDir/app/cmd/facmgr
      # Check if the systemctl service exists
      log "facmgr.service does not exist. Downloading..."
      cp $SERVICE_FILE_URL $SERVICE_FILE_PATH

      if [ -f "$source_path" ]; then
        if [ ! -d "$destination_path" ]; then
          mkdir -p "$destination_path"
        fi
      fi

      systemctl daemon-reload
      systemctl enable facmgr.service
      systemctl restart facmgr.service
      log "All services started successfully."
 
  fi

  log "facmgr_update.service does not exist. Downloading..."
  cp $SERVICE_UPDATE_FILE_URL $SERVICE_UPDATE_FILE_PATH
  cp $SERVICE_UPDATE_SCRIPT_URL /usr/bin/
  chmod 777 /usr/bin/update_script.sh
  systemctl daemon-reload
  systemctl enable facmgr_update.service
  
  update_compose

}


system_service() {

  systemctl stop snapd.socket
  systemctl disable snapd.socket
  systemctl stop snapd
  systemctl disable snapd
  sed -i 's/\$nrconf{kernelhints} = .*/\$nrconf{kernelhints} = 0;/' /etc/needrestart/needrestart.conf

}

function check_command {
  if [ $? -eq 0 ]; then
    log "$1 successfully installed."
  else
    log "Failed to install $1. Please check your network connection and try again."
    exit 1
  fi
}


function install_docker {

    apt install -y apt-transport-https ca-certificates curl software-properties-common gnupg lsb-release

    rm -f /usr/share/keyrings/docker-archive-keyring.gpg
    sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
    echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

}

# Function to check if a package is installed
function is_package_installed() {
    if dpkg -s $1 >/dev/null 2>&1; then
        return 0
    else
        return 1
    fi
}

# Function to install a package if it is not already installed
function install_package() {
    MAX_RETRIES=3
    RETRIES=0

    if ! is_package_installed $1; then
        while [ $RETRIES -lt $MAX_RETRIES ]; do
            log "Installing $1..."
            apt-get install -y $1
            if [ $? -eq 0 ]; then
                log "$1 successfully installed."
                break
            else
                RETRIES=$((RETRIES + 1))
                log "Failed to install $1. Retrying... (Attempt $RETRIES)"
            fi
        done

        if [ $RETRIES -eq $MAX_RETRIES ]; then
            log "Failed to install $1 after $MAX_RETRIES attempts. Please check your network connection and try again."
            exit 1
        fi
    else
        log "$1 is already installed. Skipping..."
    fi
}

package_install(){
  if [ -f /var/lib/dpkg/lock ]; then
    rm /var/lib/dpkg/lock
  fi
  dpkg --configure -a
 

  if ! dpkg -s sqlite3 &>/dev/null; then
    install_package sqlite3
    check_command "sqlite3"
  fi

  if ! dpkg -s docker-ce &>/dev/null; then
    install_docker
    install_package docker-ce
    check_command "docker-ce"
  fi

  if ! dpkg -s docker-compose &>/dev/null; then
    install_package docker-compose
    check_command "docker-compose"
  fi

  if ! dpkg -s jq &>/dev/null; then
    install_package jq
    check_command "jq"
  fi
 
  if ! dpkg -s net-tools &>/dev/null; then
    install_package net-tools
    check_command "net-tools"
  fi


}

cron_job(){
  # Define cron jobs
  BACKUP_JOB_IDENTIFIER="# FACMGR_DB_BACKUP_JOB"
  CRON_JOB_BACKUP="$BACKUP_JOB_IDENTIFIER\n0 1 * * * /usr/bin/env sqlite3 $FACMGR_DB '.backup '$BACKUP_DIR/db_backup_'\$(date +\%Y\%m\%d\%H\%M)'.sqlite'"

  CLEANUP_JOB_IDENTIFIER="# FACMGR_DB_CLEANUP_JOB"
  CRON_JOB_CLEANUP="$CLEANUP_JOB_IDENTIFIER\n0 2 * * * /usr/bin/env find $BACKUP_DIR -name 'db_backup_*.sqlite' -mtime +30 -delete"

  # Add the backup cron job if it does not exist
  if ! crontab -l | grep -q "$BACKUP_JOB_IDENTIFIER"; then
    (crontab -l 2>/dev/null; echo -e "$CRON_JOB_BACKUP") | crontab -
  fi

  # Add the cleanup cron job if it does not exist
  if ! crontab -l | grep -q "$CLEANUP_JOB_IDENTIFIER"; then
    (crontab -l 2>/dev/null; echo -e "$CRON_JOB_CLEANUP") | crontab -
  fi
}


add_oper_log(){
mkdir -p "$(dirname "$script_path")"
mkdir -p "$log_dir"

cat << 'EOF' > "$script_path"

{
  if [ ! -d /var/log/operation ]
  then
      mkdir /var/log/operation
      if [ `id -u` -eq 0 ]
      then
          chattr +a /var/log/operation
      fi
  fi

  file=/var/log/operation/`date '+%y-%m-%d'`.log
  if [ ! -f $file ]
  then
      touch $file
      chmod 777 $file
  fi

  echo $(date "+%y-%m-%d %T ## $(who am i |awk "{print \$1\" \"\$2\" \"\$5}") ## $(pwd) ## $(history 1 | sed 's/^[ \t]*//g' |cut -d " " -f2-)";) >> $file
} 2>/dev/null




EOF

chmod +x "$script_path"

if ! grep -q "PROMPT_COMMAND=$script_path" "$profile_path"; then
  echo "PROMPT_COMMAND=$script_path" >> "$profile_path"
  source "$profile_path"
fi
}

get_current_version() {
    if [ -f "/opt/.version" ]; then
        cat "/opt/.version"
    fi
}

# Function to update the version number and write to the file
update_version() {
    local current_version=$(get_current_version)
    echo "$new_version" > "/opt/.version"

}


cron_upgrade() {

    command_to_run="curl $DownPath/install_facmgr.sh | bash -u"
    logfile="/var/log/facmgr_cron.log"

    existing_cron=$(crontab -l 2>/dev/null)
    if [[ $existing_cron == *"curl $DownPath"* ]]; then
        new_cron=$(echo "$existing_cron" | grep -v "curl $DownPath")
        echo "$new_cron" | crontab -
        log "Existing cron job(s) with '$command_to_run' removed"
    fi

    #(crontab -l 2>/dev/null; echo "0 0 * * * $command_to_run >> $logfile 2>&1") | crontab -
    #echo "New cron job added: $command_to_run"
    #/usr/sbin/service cron restart

}



main() {
  check_root
  create_log
  for dir in "${DIRS[@]}"; do
    create_directory "$dir"
  done
  check_domain_accessibility "dl.fogworks.io" 3
  system_service
  package_install
  #update_dns
  add_limit 
  facmgr_install
  add_oper_log
  cron_job 
  update_version
  cron_upgrade
}

main
log "########## facmgr service initialization module installation completed.##########"
