#!/bin/bash

#set -x

. `dirname $0`/autoscripts/functions
. `dirname $0`/functions

THIS_SCRIPT_NAME="`basename $0`"
DB_NAME="dbackup3"
RP_CHECK_SCRIPT_NAME="rp_check.sh"

help () {
    cat <<EOF
Usage: ./$THIS_SCRIPT_NAME [OPTIONS]

  -h|--help                   Show help info.
  -s|--start_cluster          Start cluster.
  -p|--pre_start_cluster      Pre start cluster.
  -r|--reconfig_high          Reconfig high.
  -m|--manual_switch          Manual switch.
  --start-k                   systemctl start dbackup3-keepalived.
  --stop-k                    systemctl stop dbackup3-keepalived.
  --stat-k                    systemctl status dbackup3-keepalived.
  --start-b                   systemctl start dbackup3-backupd.
  --stop-b                    systemctl stop dbackup3-backupd.
  --stat-b                    systemctl status dbackup3-backupd.
  --restart-c                 systemctl restart cron.
  --start-c                   systemctl start cron.
  --stop-c                    systemctl stop cron.
  --stat-c                    systemctl status cron.
  --add-rp                    Add rp_check.sh to crontab.
  --del-rp                    Delete rp_check.sh from crontab.
  --stat-db                   Run some common database status commands on the local database.
EOF
    exit 1
}

start_cluster () {
    local result=
    local delay=${START_CLUSTER_DELAY:=3}

    if [ -z "$PEER_HOST_ADDRESS_LIST" ]; then
        echo "Parameter 'PEER_HOST_ADDRESS_LIST' must be \
configured in the configuration file config_def."
        return 1
    fi

    local ip_address="`get_available_ip_address`"
    if [ -z "$ip_address" ]; then
        echo "The $THIS_SCRIPT_NAME, there is no IP address in \
($PEER_HOST_ADDRESS_LIST) that can be successfully connected, \
Unable to know the status of the peer host."
        return
    fi

    result=`local_db_execute_query "SHOW SLAVE STATUS\G" false`
    if [ $? -ne 0 ]; then
        echo "Failed to execute 'SHOW SLAVE STATUS\G' on the local database, \
Please check the database account password and other configurations."
        return 1
    fi

    if [ -z "$result" ]; then
        echo "local host is master"
        start_keepalived_service
        start_backupd
        sleep $delay
        result=`ssh_execute_cmd "$PEER_HOST_USER_NAME@$ip_address" \
'systemctl start dbackup3-keepalived'`
        if [ $? -ne 0 ]; then
            echo "Failed to execute command 'systemctl start dbackup3-keepalived' \
on the remote host($ip_address), error($result)."
            return 1
        fi
    else
        echo "local host is slave"
    fi

    result=`peer_db_execute_query "$ip_address" "SHOW SLAVE STATUS\G" false`
    if [ $? -ne 0 ]; then
        echo "Failed to execute 'SHOW SLAVE STATUS\G' on the remote database($ip_address), \
Please check the database account password and other configurations."
        return 1
    fi

    if [ -z "$result" ]; then
        echo "remote host is master"
        result=`ssh_execute_cmd "$PEER_HOST_USER_NAME@$ip_address" \
'systemctl start dbackup3-keepalived; systemctl start dbackup3-backupd'`
        if [ $? -ne 0 ]; then
            echo "Failed to execute command 'systemctl start dbackup3-keepalived; \
systemctl start dbackup3-backupd' on the remote host($ip_address), error($result)."
            return 1
        fi
        sleep $delay
        start_keepalived_service
    else
        echo "remote host($ip_address) is slave"
    fi

    echo "The cluster was started successfully."
}

pre_start_cluster () {
    local result=
    result=`local_db_execute_query "SHOW SLAVE STATUS\G" false`
    if [ $? -eq 0 ]; then
        if [ -z "$result" ]; then
            echo "local host is master"
        else
            echo "local host is slave"
        fi
    else
        echo "Failed to execute 'SHOW SLAVE STATUS\G' on local database service."
        return
    fi

    local ip_address="`get_available_ip_address`"
    if [ -z "$ip_address" ]; then
        echo "The $THIS_SCRIPT_NAME, there is no IP address in \
($PEER_HOST_ADDRESS_LIST) that can be successfully connected, \
Unable to know the status of the peer host."
        return
    fi

    result=`peer_db_execute_query "$ip_address" "SHOW SLAVE STATUS\G" false`
    if [ $? -eq 0 ]; then
        if [ -z "$result" ]; then
            echo "remote host($ip_address) is master"
        else
            echo "remote host($ip_address) is slave"
        fi
    else
        echo "Failed to execute 'SHOW SLAVE STATUS\G' on \
remote($ip_address) database service."
    fi
}

reconfig_ha () {
    local script_name="$1"
    local result=
    local ip_address="`get_available_ip_address`"
    if [ -z "$ip_address" ]; then
        echo "The $THIS_SCRIPT_NAME, there is no IP address in \
($PEER_HOST_ADDRESS_LIST) that can be successfully connected, \
Unable to know the status of the peer host."
        return
    fi

    stop_backupd
    echo "The $script_name, stop dbackup3-backupd sucess."

    result=`local_db_execute_query "flush privileges; unlock tables; stop slave; reset slave all;" true`
    if [ $? -ne 0 ]; then
        echo "The $script_name, database service reset slave error:($result)"
        return
    fi

    echo "The $script_name, mysql reset slave."

    local binlog_sql="FLUSH TABLE WITH READ LOCK; SHOW MASTER STATUS; UNLOCK TABLES;"
    result=`peer_db_execute_query "$ip_address" "$binlog_sql" false`
    if [ $? -ne 0 ]; then
        echo "The $script_name, execution of SQL statement \
'$binlog_sql;' on remote host $ip_address fails."
        return 1
    fi

    peer_db_dump_data "$ip_address" $DB_NAME
    if [ $? -ne 0 ]; then
        echo "The $script_name, the peer host($ip_address) database export $DB_NAME fails."
        return
    fi

    if ! [ -f "$DUMP_OUTPUT_PATH" ]; then
        echo "The $script_name, file $DUMP_OUTPUT_PATH does not exist."
        return
    fi

    echo "The $script_name, remote($ip_address) mysql backup sucess."

    local_db_restore_data $DB_NAME
    if [ $? -ne 0 ]; then
        echo "The $script_name, mysql restore (from $DUMP_OUTPUT_PATH to $DB_NAME ) failed."
        return
    fi

    echo "The $script_name, mysql restore (from $ip_address to $DB_LOCAL_ADDRESS ) sucess."

    local file=`echo "$result" | grep -v File |awk '{print $1}'`
    local position=`echo "$result" | grep -v File |awk '{print $2}'`

    local change_master_cmd=`gen_change_replication_cmd "$ip_address"\
                                "$DB_PEER_PORT" "$file" "$position"`
    result=`local_db_execute_query "$change_master_cmd" true`
    if [ $? -ne 0 ]; then
        echo "The $script_name, failed to change to slave($result),cmd:[$change_master_cmd]."
        return
    fi

    echo "The $script_name, mysql lock, change to slave sucess."
}

manual_switch () {
    local script_name="$1"
    local delay=${MANUAL_SWITCH_DELAY:=120}
    local result=
    local log_msg=
    local slave_sql_running_state=

    local ip_address="`get_available_ip_address`"
    if [ -z "$ip_address" ]; then
        log_msg="There is no IP address in \
($PEER_HOST_ADDRESS_LIST) that can be successfully connected, \
Unable to know the status of the peer host."
        echo "$log_msg"
        write_switch_log "$log_msg"
        return
    fi

    result=`local_db_execute_query "SHOW SLAVE STATUS\G" false`
    if [ $? -ne 0 ]; then
        log_msg="Execution of the SQL statement SHOW SLAVE STATUS \
failed on local database service."
        echo "$log_msg"
        write_switch_log "$log_msg"
        return
    fi

    if [ -n "$result" ]; then
        log_msg="The local database service is currently a slave node and cannot be \
manually switched."
        echo "$log_msg"
        write_switch_log "$log_msg"
        return
    fi

    stop_backupd
    echo "After $delay seconds, continue to execution of the SQL statement \
'flush logs' and stop keepalived service."
    sleep $delay

    while true; do
        ip_address="`get_available_ip_address`"
        if [ -z "$ip_address" ]; then
            log_msg="There is no IP address in ($PEER_HOST_ADDRESS_LIST) that \
can be successfully connected, Unable to know the status of the peer host."
            echo "$log_msg"
            write_switch_log "$log_msg"
            return
        fi

        result=`peer_db_execute_query "$ip_address" "SHOW SLAVE STATUS\G" false`
        if [ $? -ne 0 ]; then
            log_msg="Execution of the SQL statement SHOW SLAVE STATUS \
failed on remote($ip_address) database service."
            echo "$log_msg"
            write_switch_log "$log_msg"
            return
        fi

        if [ -z "$result" ]; then
            log_msg="No slave status available."
            echo "$log_msg"
            write_switch_log "$log_msg"
            break
        fi

        slave_sql_running_state=$(echo "$result" | grep "Slave_SQL_Running_State:" | awk -F': ' '{print $2}')

        # Check if Slave_SQL_Running_State is the specified state
        if [ -z "$slave_sql_running_state" ]; then
            log_msg="Slave_SQL_Running_State is null."
            echo "$log_msg"
            write_switch_log "$log_msg"
            break
        fi

        check_relay_all_log "$slave_sql_running_state"
        if [ $? -eq 0 ]; then
            log_msg="Binlog has been fully applied. State: $slave_sql_running_state"
            echo "$log_msg"
            write_switch_log "$log_msg"
            break
        else
            log_msg="Current state: $slave_sql_running_state. \
Waiting for binlog to be applied..."
            echo "$log_msg"
            write_switch_log "$log_msg"
            sleep $WAIT_BINLOG_DELAY
        fi
    done

    stop_keepalived_service
    log_msg="Manually perform a switch."
    echo "$log_msg"
    write_switch_log "$log_msg"
}

add_rp_check () {
    local file_path="`realpath $BEST_PRACTICE_PATH/$RP_CHECK_SCRIPT_NAME`"
    if ! [ -f "$file_path" ]; then
        echo "File $file_path does not exist!"
    fi

    if crontab -l | grep -q "$RP_CHECK_SCRIPT_NAME"; then
        crontab -l | grep -v "$RP_CHECK_SCRIPT_NAME" | crontab -
    fi

    local interval=${RP_CHECK_INTERVAL:=1} # minutes unit
    (crontab -l; echo "*/$interval * * * * $file_path") | crontab -

    crontab -l
}

delete_rp_check () {
    if crontab -l | grep -q "$RP_CHECK_SCRIPT_NAME"; then
        crontab -l | grep -v "$RP_CHECK_SCRIPT_NAME" | crontab -
    fi

    crontab -l
}

stat_db () {
    local_db_show_status "show status;"
    local_db_show_status "show master status\G"
    local_db_show_status "show slave status\G"
    local_db_show_status "show global variables like '%semi%'\G"
    local_db_show_status "show variables like '%semi%'\G"
    local_db_show_status "show global status like '%semi%'\G"
    local_db_show_status "show status like '%semi%'\G"
    if [ "$DB_PRODUCT_NAME" != "mariadb" ]; then
        local_db_show_status "select * from performance_schema.replication_applier_status_by_worker\G"
    fi
}

if [ $# -eq 0 ]; then
    help
fi

while true; do
    case "$1" in
    -h|--help)
        help
        break
        ;;
    -s|--start_cluster)
        start_cluster
        break
        ;;
    -p|--pre_start_cluster)
        pre_start_cluster
        break
        ;;
    -r|--reconfig_high)
        reconfig_ha "$THIS_SCRIPT_NAME"
        break
        ;;
    -m|--manual_switch)
        manual_switch "$THIS_SCRIPT_NAME"
        break
        ;;
    --start-k)
        service_control dbackup3-keepalived start
        break
        ;;
    --stop-k)
        service_control dbackup3-keepalived stop
        break
        ;;
    --stat-k)
        systemctl status dbackup3-keepalived
        break
        ;;
    --start-b)
        service_control dbackup3-backupd start
        break
        ;;
    --stop-b)
        service_control dbackup3-backupd stop
        break
        ;;
    --stat-b)
        service_control  dbackup3-backupd status
        break
        ;;
    --restart-c)
        service_control cron restart
        break
        ;;
    --start-c)
        service_control cron start
        break
        ;;
    --stop-c)
        service_control cron stop
        break
        ;;
    --stat-c)
        service_control cron status
        break
        ;;
    --add-rp)
        add_rp_check
        break
        ;;
    --del-rp)
        delete_rp_check
        break
        ;;
    --stat-db)
        stat_db
        break
        ;;
    --)
        break
        ;;
    *)
        echo "Unsupported command $1."
        help
        ;;
    esac
done
