#!/bin/bash

# === Константы для подключения к БД ===
MASTER_IP=""
SLAVE_IP=""
MASTER_MAIL_FQDN=""
REPLICATION_USER="replication_user"
REPLICATION_PASS="replication_password"
LOG_FILE="/var/log/switch_postgres.log"

# === Константы для cddisk (appsettings.json) ===
CDDISK_DB_NAME="cddisk"
CDDISK_DB_USER="cddisk"
CDDISK_DB_PASS="cddisk"
CDDISK_DB_PORT="5432"

# === Константы для documentserver (local.json) ===
DS_DB_NAME="ds"
DS_DB_USER="ds"
DS_DB_PASS="ds"
DS_DB_PORT="5432"

# === Константы для почтового сервера (postfix, dovecot) ===
MAIL_DB_NAME="postfix"
MAIL_DB_USER="postfix"
MAIL_DB_PASS="postfix"
MAIL_DB_PORT="5432"

# === Константы для java-maker (external.properties) ===
JAVA_DB_NAME="pagesdb"
JAVA_DB_PORT="5432"

# === Определение ОС и динамических путей PostgreSQL ===
if [ -f /etc/os-release ]; then
    . /etc/os-release
    DETECTED_OS=$ID
else
    DETECTED_OS="unknown"
fi

if [ "$DETECTED_OS" = "redos" ] || [ "$DETECTED_OS" = "centos" ] || [ "$DETECTED_OS" = "rhel" ]; then
    PG_DATA=$(sudo -u postgres psql -t -P format=unaligned -c "SHOW data_directory;" 2>/dev/null || echo "/var/lib/pgsql/data")
    PG_BIN="$(dirname "$(sudo -u postgres which psql 2>/dev/null)" || echo "/usr/bin")"

elif [ "$DETECTED_OS" = "astra" ] || [ "$DETECTED_OS" = "debian" ] || [ "$DETECTED_OS" = "ubuntu" ]; then
    PG_DATA=$(sudo -u postgres psql -t -P format=unaligned -c "SHOW data_directory;" 2>/dev/null)
    
    if [ -z "$PG_DATA" ]; then
        PG_VER=$(ls /etc/postgresql/ 2>/dev/null | sort -V | tail -n 1)
        if [ -n "$PG_VER" ]; then
            PG_DATA="/var/lib/postgresql/$PG_VER/main"
            PG_BIN="/usr/lib/postgresql/$PG_VER/bin"
        else
            PG_DATA="/var/lib/postgresql/15/main"
            PG_BIN="/usr/lib/postgresql/15/bin"
        fi
    else
        PG_VER=$(echo "$PG_DATA" | awk -F'/' '{print $5}')
        PG_BIN="/usr/lib/postgresql/$PG_VER/bin"
    fi
else
    PG_DATA="/var/lib/pgsql/data"
    PG_BIN="/usr/bin"
fi

# === Массивы путей к конфигурациям ===
declare -a postfix_configs=(
    "/etc/postfix/pgsql/virtual_alias_maps.cf"
    "/etc/postfix/pgsql/virtual_mailbox_domains.cf"
    "/etc/postfix/pgsql/virtual_mailbox_maps.cf"
)

declare -a dovecot_configs=(
    "/etc/dovecot/dovecot-pgsql.conf"
)

declare -a cs_ds_configs=(
    "/opt/r7-office/Api/appsettings.json"
    "/opt/r7-office/Sso.Api/appsettings.json"
    "/opt/r7-office/Processing/appsettings.json"
    "/etc/r7-office/documentserver/local.json"
)

declare -a cs_configs=(
    "/opt/r7-office/Api/appsettings.json"
    "/opt/r7-office/Sso.Api/appsettings.json"
    "/opt/r7-office/Processing/appsettings.json"
)

declare -a cs_java_configs=(
    "/opt/r7-office/java-maker/external.properties"
)


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

function check_superuser() {
    if [[ $EUID -ne 0 ]]; then
        log "Ошибка: Скрипт должен запускаться от root."
        exit 1
    fi
}

function get_local_ip() {
    hostname -I | awk '{print $1}'
}

function get_local_hostname() {
    hostname | awk '{print $1}'
}

function backup_file_if_needed() {
    local file="$1"
    local bak_file="${file}.bak"

    if [[ ! -f "$bak_file" ]]; then
        cp "$file" "$bak_file"
        log "Создана резервная копия: $bak_file"
    fi
}

function restore_from_backup() {
    local file="$1"
    local bak_file="${file}.bak"

    if [[ -f "$bak_file" ]]; then
        log "Восстановление файла $file из резервной копии..."
        cp "$bak_file" "$file"
    else
        log "⚠️ Резервная копия для $file не найдена. Пропущено."
    fi
}

function restore_all_configs() {
    log "Начало восстановления конфигураций из резервных копий..."

    for file in "${cs_ds_configs[@]}"; do
        restore_from_backup "$file"
    done

    for file in "${postfix_configs[@]}"; do
        restore_from_backup "$file"
    done

    for file in "${dovecot_configs[@]}"; do
        restore_from_backup "$file"
    done

    for file in "${cs_java_configs[@]}"; do
        restore_from_backup "$file"
    done

    log "✅ Восстановление завершено."
}

function extract_cddisk_db_credentials() {
    local file="/opt/r7-office/Api/appsettings.json"
    if [[ ! -f "$file" ]]; then
        log "Файл $file не найден."
        return 1
    fi

    # Извлекаем строку подключения
    local line
    line=$(grep -A2 '"R7StorageServerUserActions"' "$file" | tr -d '\n')
    if [[ -z "$line" ]]; then
        log "Строка R7StorageServerUserActions не найдена в $file"
        return 1
    fi

    local conn_str
    conn_str=$(echo "$line" | sed -E 's/.*"R7StorageServerUserActions"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/')
    if [[ -z "$conn_str" ]]; then
        log "Не удалось извлечь строку подключения из $file"
        return 1
    fi

    DB_NAME=$(echo "$conn_str" | grep -oP 'Database=\K[^;]+')
    DB_USER=$(echo "$conn_str" | grep -oP 'Username=\K[^;]+')
    DB_PASS=$(echo "$conn_str" | grep -oP 'Password=\K[^;]+')
    DB_HOST=$(echo "$conn_str" | grep -oP 'Host=\K[^;]+')
    DB_PORT=$(echo "$conn_str" | grep -oP 'Port=\K[^;]*')
    DB_PORT="${DB_PORT:-5432}"
    if [[ -z "$DB_NAME" || -z "$DB_HOST" ]]; then
        log "В строке подключения отсутствуют необходимые параметры (Database и Host)."
        return 1
    fi
    export DB_NAME DB_USER DB_PASS DB_HOST DB_PORT
}

function extract_documentserver_db_credentials() {
    local config="/etc/r7-office/documentserver/local.json"
    if [[ ! -f "$config" ]]; then
        log "⚠️ Файл $config не найден."
        return 1
    fi
    DS_DB_HOST=$(grep '"dbHost"' "$config" | awk -F '"' '{print $4}')
    DS_DB_NAME=$(grep '"dbName"' "$config" | awk -F '"' '{print $4}')
    DS_DB_USER=$(grep '"dbUser"' "$config" | awk -F '"' '{print $4}')
    DS_DB_PASS=$(grep '"dbPass"' "$config" | awk -F '"' '{print $4}')
    DS_DB_PORT=$(grep '"dbPort"' "$config" | awk -F '"' '{print $4}')
    DS_DB_PORT="${DS_DB_PORT:-5432}"
    if [[ -z "$DS_DB_HOST" || -z "$DS_DB_USER" || -z "$DS_DB_PASS" ]]; then
        log "⚠️ В файле local.json отсутствуют данные для подключения к БД."
        return 1
    fi
    export DS_DB_HOST DS_DB_NAME DS_DB_USER DS_DB_PASS DS_DB_PORT
}

function check_db_connection_after_change() {
    local new_master="$1"
    log "Проверка подключения к БД с новыми параметрами..."

    # === cddisk: используем константы с обновлённым Host ===
    local db_name="$CDDISK_DB_NAME"
    local db_user="$CDDISK_DB_USER"
    local db_pass="$CDDISK_DB_PASS"
    local db_host="$new_master"
    local db_port="${CDDISK_DB_PORT:-5432}"
    log "Попытка подключения (cddisk): Host=$db_host, User=$db_user, Database=$db_name, Port=$db_port"
    echo "$db_pass" | PGPASSWORD="$db_pass" psql -h "$db_host" -U "$db_user" -p "$db_port" -d "$db_name" -c "\q" > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        log "✅ Успешное подключение к cddisk"
    else
        log "❌ Не удалось подключиться к cddisk"
        return 1
    fi

    # === documentserver: используем DS_* константы с обновлённым Host ===
    local ds_name="$DS_DB_NAME"
    local ds_user="$DS_DB_USER"
    local ds_pass="$DS_DB_PASS"
    local ds_host="$new_master"
    local ds_port="${DS_DB_PORT:-5432}"

    log "Попытка подключения (documentserver): Host=$ds_host, User=$ds_user, Database=$ds_name, Port=$ds_port"
    echo "$ds_pass" | PGPASSWORD="$ds_pass" psql -h "$ds_host" -U "$ds_user" -p "$ds_port" -d "$ds_name" -c "\q" > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        log "✅ Успешное подключение к documentserver"
    else
        log "❌ Не удалось подключиться к documentserver"
        return 1
    fi

    # === mail: используем MAIL_* константы с обновлённым Host ===
    local ds_name="$MAIL_DB_NAME"
    local ds_user="$MAIL_DB_USER"
    local ds_pass="$MAIL_DB_PASS"
    local ds_host="$new_master"
    local ds_port="${MAIL_DB_PORT:-5432}"

    log "Попытка подключения (postfix): Host=$ds_host, User=$ds_user, Database=$ds_name, Port=$ds_port"
    echo "$ds_pass" | PGPASSWORD="$ds_pass" psql -h "$ds_host" -U "$ds_user" -p "$ds_port" -d "$ds_name" -c "\q" > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        log "✅ Успешное подключение к postfix"
    else
        log "❌ Не удалось подключиться к postfix"
        return 1
    fi

    # === javamaker: используем JAVA_* константы с обновлённым Host ===
    local ds_name="$JAVA_DB_NAME"
    local ds_user="$CDDISK_DB_USER"
    local ds_pass="$CDDISK_DB_PASS"
    local ds_host="$new_master"
    local ds_port="${JAVA_DB_PORT:-5432}"

    log "Попытка подключения (pagesdb): Host=$ds_host, User=$ds_user, Database=$ds_name, Port=$ds_port"
    echo "$ds_pass" | PGPASSWORD="$ds_pass" psql -h "$ds_host" -U "$ds_user" -p "$ds_port" -d "$ds_name" -c "\q" > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        log "✅ Успешное подключение к pagesdb"
    else
        log "❌ Не удалось подключиться к pagesdb"
        return 1
    fi

    return 0
}

function extract_mail_db_credentials() {
    local file="/etc/dovecot/dovecot-pgsql.conf"

    if [[ ! -f "$file" ]]; then
        log "Файл $file не найден."
        return 1
    fi

    DB_NAME=$(grep -E "dbname\s*=\s*+"  "$file" | awk -F"=" '{print $2}') | sed 's/^[[:space:]]*//; s/[[:space:]]*$//'
    if [[ -z "$DB_NAME" ]]; then
        log "Строка dbname =  не найдена в $file"
        return 1
    fi

    DB_USER=$(grep -E "user\s*=\s*+"  "$file" | awk -F"=" '{print $2}') | sed 's/^[[:space:]]*//; s/[[:space:]]*$//'
    if [[ -z "$DB_USER" ]]; then
        log "Строка user =  не найдена в $file"
        return 1
    fi

    DB_PASS=$(grep -E "password\s*=\s*+"  "$file" | awk -F"=" '{print $2}') | sed 's/^[[:space:]]*//; s/[[:space:]]*$//'
    if [[ -z "$DB_PASS" ]]; then
        log "Строка password =  не найдена в $file"
        return 1
    fi

    DB_HOST=$(grep -E "hosts\s*=\s*[^\:]+:"  "$file" | awk '{print $3}'| awk -F":" '{print $1}') | sed 's/^[[:space:]]*//; s/[[:space:]]*$//'
    if [[ -z "$DB_HOST" ]]; then
        log "Строка hosts =  не найдена в $file"
        return 1
    fi

    DB_PORT=$(grep -E "hosts\s*=\s*[^\:]+:"  "$file" | awk '{print $3}'| awk -F":" '{print $2}') | sed 's/^[[:space:]]*//; s/[[:space:]]*$//'
    if [[ -z "$DB_PORT" ]]; then
        log "Строка hosts = <IP>:<PORT>  не найдена в $file"
        return 1
    fi

    DB_PORT="${DB_PORT:-5432}"

    if [[ -z "$DB_NAME" || -z "$DB_HOST" ]]; then
        log "В строке подключения отсутствуют необходимые параметры (Database и Host)."
        return 1
    fi

    export DB_NAME DB_USER DB_PASS DB_HOST DB_PORT
}

function check_db_connection() {
    log "Проверка подключения к БД с текущими параметрами..."

    # === cddisk ===
    if extract_cddisk_db_credentials; then
        local db_host="$DB_HOST"
        local db_name="$DB_NAME"
        local db_user="$DB_USER"
        local db_pass="$DB_PASS"
        local db_port="${DB_PORT:-5432}"

        log "Попытка подключения (cddisk): Host=$db_host, User=$db_user, Database=$db_name, Port=$db_port"

        echo "$db_pass" | PGPASSWORD="$db_pass" psql -h "$db_host" -U "$db_user" -p "$db_port" -d "$db_name" -c "SELECT version();" > /dev/null 2>&1

        if [ $? -eq 0 ]; then
            log "Успешное подключение к БД от пользователя $db_user"
        else
            log "Не удалось подключиться к БД от пользователя $db_user. Проверьте настройки доступа или пароль."
        fi
    else
        log "⚠️ Пропущена проверка cddisk: не удалось получить данные из appsettings.json"
    fi

    # === documentserver ===
    if extract_documentserver_db_credentials; then
        local ds_host="$DS_DB_HOST"
        local ds_name="$DS_DB_NAME"
        local ds_user="$DS_DB_USER"
        local ds_pass="$DS_DB_PASS"
        local ds_port="$DS_DB_PORT"

        log "Попытка подключения (documentserver): Host=$ds_host, User=$ds_user, Database=$ds_name, Port=$ds_port"

        echo "$ds_pass" | PGPASSWORD="$ds_pass" psql -h "$ds_host" -U "$ds_user" -p "$ds_port" -d "$ds_name" -c "SELECT version();" > /dev/null 2>&1

        if [ $? -eq 0 ]; then
            log "Успешное подключение к БД от пользователя $ds_user"
        else
            log "Не удалось подключиться к БД от пользователя $ds_user. Проверьте настройки доступа или пароль."
        fi
    else
        log "⚠️ Пропущена проверка documentserver: не удалось получить данные из local.json"
    fi

    # === mail ===
    if extract_mail_db_credentials; then
        local db_host="$DB_HOST"
        local db_name="$DB_NAME"
        local db_user="$DB_USER"
        local db_pass="$DB_PASS"
        local db_port="${DB_PORT:-5432}"

        log "Попытка подключения (postfix): Host=$db_host, User=$db_user, Database=$db_name, Port=$db_port"

        echo "$db_pass" | PGPASSWORD="$db_pass" psql -h "$db_host" -U "$db_user" -p "$db_port" -d "$db_name" -c "SELECT version();" > /dev/null 2>&1

        if [ $? -eq 0 ]; then
            log "Успешное подключение к БД от пользователя $db_user"
        else
            log "Не удалось подключиться к БД от пользователя $db_user. Проверьте настройки доступа или пароль."
        fi
    else
        log "⚠️ Пропущена проверка postfix: не удалось получить данные из virtual_alias_maps.cf"
    fi

    return 0
}

function update_cddisk_configs() {
    local new_master="$1"
    log "Обновление appsettings.json для cddisk на новый мастер: $new_master..."
    local conn_user_actions="Database=$CDDISK_DB_NAME;Username=$CDDISK_DB_USER;Password=$CDDISK_DB_PASS;Host=$new_master;Port=$CDDISK_DB_PORT;"
    local conn_server="Database=$CDDISK_DB_NAME;Username=$CDDISK_DB_USER;Password=$CDDISK_DB_PASS;Host=$new_master;Port=$CDDISK_DB_PORT;"
    for file in "${cs_configs[@]}"; do
        if [[ ! -f "$file" ]]; then
            log "⚠️ Файл $file не найден, пропущено."
            continue
        fi

        backup_file_if_needed "$file"

        local old_line=$(grep -A2 '"R7StorageServerUserActions"' "$file" | tr -d '\n')
        if [[ -n "$old_line" ]]; then
            sed -i "s|\"R7StorageServerUserActions\": *\"[^\"]*\"|\"R7StorageServerUserActions\": \"$conn_user_actions\"|" "$file"
            if [[ $? -eq 0 ]]; then
                log "✅ R7StorageServerUserActions в $file обновлён"
            fi
        fi

        local old_line=$(grep -A2 '"R7StorageServer"' "$file" | tr -d '\n')
        if [[ -n "$old_line" ]]; then
            sed -i "s|\"R7StorageServer\": *\"[^\"]*\"|\"R7StorageServer\": \"$conn_server\"|" "$file"
            if [[ $? -eq 0 ]]; then
                log "✅ R7StorageServer в $file обновлён"
            fi
        fi
    done
}

function update_documentserver_config() {
    local new_master="$1"
    local config="/etc/r7-office/documentserver/local.json"
    if [[ ! -f "$config" ]]; then
        log "⚠️ Файл $config не найден, пропущено."
        return 1
    fi
    backup_file_if_needed "$config"
    current_host=$(grep '"dbHost"' "$config" | awk -F '"' '{print $4}')
    if [[ "$current_host" == "$new_master" ]]; then
        log "IP-адрес в $config уже актуален ($new_master). Изменение не требуется."
        return 0
    fi
    sed -i "s/\"dbHost[^\"]*\": *\"[^\"]*\"/\"dbHost\": \"$new_master\"/" "$config"
    if [[ $? -eq 0 ]]; then
        log "dbHost в $config успешно обновлён на $new_master"
    else
        log "❌ Ошибка обновления $config"
    fi
}

function restart_supervisor_services() {
    log "Перезапуск supervisor-сервисов..."
    supervisorctl restart all
}

function restart_documentserver_services() {
    log "Перезапуск ds-сервисов..."
    local prepare_script="/usr/bin/documentserver-prepare4shutdown.sh"
    if [[ -f "$prepare_script" ]]; then
        log "Выполняется подготовительный скрипт: $prepare_script..."
        "$prepare_script"
        if [[ $? -ne 0 ]]; then
            log "⚠️ Подготовительный скрипт завершился с ошибкой. Продолжить перезапуск? (y/n)"
            read -p "Продолжить? " confirm
            [[ "$confirm" != "y" && "$confirm" != "Y" ]] && log "Перезапуск отменён пользователем." && return 1
        fi
    fi
    local services=(
        "ds-converter.service"
        "ds-docservice.service"
        "ds-metrics.service"
    )
    for service in "${services[@]}"; do
        if systemctl is-active --quiet "$service"; then
            systemctl daemon-reload > /dev/null 2>&1
            systemctl restart "$service"
            log "$service перезапущен."
        fi
    done
    log "✅ Все актуальные ds-сервисы перезапущены."
}

function stop_documentserver_services() {
    log "Останов ds-сервисов..."
    local prepare_script="/usr/bin/documentserver-prepare4shutdown.sh"
    if [[ -f "$prepare_script" ]]; then
        "$prepare_script"
    fi
    local services=(
        "ds-converter.service"
        "ds-docservice.service"
        "ds-metrics.service"
    )
    for service in "${services[@]}"; do
        if systemctl is-active --quiet "$service"; then
            systemctl daemon-reload > /dev/null 2>&1
            systemctl stop "$service"
            log "$service остановлен."
        fi
    done
}

function update_postfix_configs() {
    local new_master="$1"
    log "Обновление файлов /etc/postfix/pgsql/* для postfix на новый мастер: $new_master..."

    for file in "${postfix_configs[@]}"; do
        if [[ ! -f "$file" ]]; then
            continue
        fi

        backup_file_if_needed "$file"

        local old_line=$(grep -E "hosts\s*=\s*[^\:]+:"  "$file" | tr -d '\n')
        if [[ -n "$old_line" ]]; then
            sed -i -E "s|hosts\s*=\s*[^\:]+:|hosts = $new_master:|" "$file"
            log "✅ hosts =  в $file обновлён"
        fi
    done
}

function update_dovecot_configs() {
    local new_master="$1"
    log "Обновление файла /etc/dovecot/dovecot-pgsql.conf для dovecot на новый мастер: $new_master..."

    for file in "${dovecot_configs[@]}"; do
        if [[ ! -f "$file" ]]; then
            continue
        fi

        backup_file_if_needed "$file"

        local old_line=$(grep -E "host=[^\ ]+"  "$file" | tr -d '\n')
        if [[ -n "$old_line" ]]; then
            sed -i -E "s|host=[^\ ]+|host=$new_master|" "$file"
            log "✅ host= в $file обновлён"
        fi
    done
}

function restart_mail_services() {
    local services=(
        "postfix.service"
        "dovecot.service"
    )

    for service in "${services[@]}"; do
        if systemctl is-active --quiet "$service"; then
            systemctl restart "$service"
            log "$service перезапущен."
        fi
    done
}

function promote_slave_to_master() {
    log "Продвижение slave в master..."

    local pg_data="$PG_DATA"
    if [[ -f "$pg_data/standby.signal" && -f "$pg_data/recovery.signal" ]]; then
        log "⚠️ Сервер не находится в режиме standby. Пропущено продвижение в master."
        return 0
    fi

    # Используем динамический путь к бинарникам (PG_BIN)
    sudo -u postgres ${PG_BIN}/pg_ctl promote -D "$pg_data"
    if [ $? -eq 0 ]; then
        log "✅ Slave успешно переведён в режим master."
    else
        log "⚠️ Не удалось продвинуть в master (возможно, уже является master)."
    fi
}

function switch_to_slave_as_master() {
    log "Начало процесса переключения slave -> master..."
    log "Используем MASTER_IP = $MASTER_IP из констант."

    check_db_connection_after_change "$MASTER_IP"
    promote_slave_to_master

    update_cddisk_configs "$MASTER_IP"
    update_documentserver_config "$MASTER_IP"

    restart_supervisor_services
    restart_documentserver_services

    log "✅ Сервер переведён в режим master."
}

function switch_to_master_as_slave() {
    log "Начало процесса переключения master -> slave..."
    log "Используем MASTER_IP = $MASTER_IP для создания реплики."
    read -p "Вы уверены, что хотите сделать этот сервер slave? Это очистит данные. (y/n): " confirm
    [[ "$confirm" != "y" ]] && log "Операция отменена пользователем." && exit 1

    if [[ -z "$REPLICATION_PASS" ]]; then
        log "❌ Пароль не может быть пустым."
        exit 1
    fi

    log "Остановка PostgreSQL..."
    systemctl stop postgresql

    log "Очистка каталога данных PostgreSQL..."
    # Используем PG_DATA из настроек
    rm -rf "${PG_DATA}"/*
    mkdir -p "${PG_DATA}"

    log "Создание новой реплики с мастера: $MASTER_IP..."

    sudo -u postgres env PGPASSWORD="$REPLICATION_PASS" ${PG_BIN}/pg_basebackup \
        -h "$MASTER_IP" \
        -D "${PG_DATA}" \
        -U "$REPLICATION_USER" \
        -P -R

    if [ $? -ne 0 ]; then
        log "❌ Ошибка при создании реплики. Проверьте доступность мастера и учётные данные."
        exit 1
    fi

    log "Запуск PostgreSQL..."
    systemctl start postgresql

    check_db_connection_after_change "$MASTER_IP"
    update_cddisk_configs "$MASTER_IP"
    update_documentserver_config "$MASTER_IP"

    restart_supervisor_services
    restart_documentserver_services

    log "✅ Сервер успешно переведён в режим slave."
}

function show_current_configurations() {
    echo -e "\n=== Текущие конфигурации с подключением к БД ==="
    echo "Файлы appsettings.json (только актуальные):"

    for file in "${cs_configs[@]}"; do
        if [[ ! -f "$file" ]]; then
            echo "  $file — не найден"
            continue
        fi

        echo "  === $file ==="

        local user_actions=$(grep -A2 '"R7StorageServerUserActions"' "$file" | tr -d '\n' | sed 's/[",]//g; s/:[ ]*/:/g')
        if [[ -n "$user_actions" ]]; then
            echo "  R7StorageServerUserActions: ${user_actions#*R7StorageServerUserActions: }"
        else
            echo "  R7StorageServerUserActions: не найден"
        fi

        local storage_server=$(grep -A2 '"R7StorageServer"' "$file" | tr -d '\n' | sed 's/[",]//g; s/:[ ]*/:/g')
        if [[ -n "$storage_server" ]]; then
            echo "  R7StorageServer: ${storage_server#*R7StorageServer: }"
        else
            echo "  R7StorageServer: не найден"
        fi

        echo ""
    done

    local doc_config="/etc/r7-office/documentserver/local.json"
    echo "Файл local.json (documentserver):"
    if [[ -f "$doc_config" ]]; then
        grep -E '"(dbHost|dbName|dbUser|dbPass|dbPort)"' "$doc_config" | sed 's/^/  /'
    else
        echo "  Файл не найден"
    fi
}

function show_current_configurations_postfix() {
    echo -e "\n=== Текущие конфигурации POSTFIX, подключение к БД ==="
    for file in "${postfix_configs[@]}"; do
        if [[ ! -f "$file" ]]; then
            continue
        fi
        echo "  === $file ==="
        grep -E "(hosts|user|password|dbname)" "$file"
        echo ""
    done
}

function show_current_configurations_dovecot() {
    echo -e "\n=== Текущие конфигурации Dovecot, подключение к БД ==="
    for file in "${dovecot_configs[@]}"; do
        if [[ ! -f "$file" ]]; then
            continue
        fi
        echo "  === $file ==="
        grep -E "(connect = )" "$file"
        echo ""
    done
}

function get_postgres_data_dir() {
    local dir="${PG_DATA}"
    if [[ -d "$dir" ]]; then
        echo "$dir"
        return 0
    else
        log "❌ Каталог данных PostgreSQL не найден."
        return 1
    fi
}

function get_postgres_role() {
    local pg_data="${PG_DATA}"
    local cur_ip="$1"

    if systemctl is-active --quiet postgresql > /dev/null 2>&1; then
        local role_sql=$(sudo -u postgres psql -h $cur_ip -tAc "SELECT pg_is_in_recovery();")
        if [[ $? -eq 0 ]]; then
            if [[ "$(echo "$role_sql" | tr '[:upper:]' '[:lower:]')" == "f" ]]; then
                echo "master"
                return 0
            else
                echo "slave"
                return 0
            fi
        fi
    fi

    if [[ -f "$pg_data/standby.signal" ]]; then
        echo "slave"
        return 0
    elif [[ -f "$pg_data/postmaster.pid" ]]; then
        echo "master"
        return 0
    else
        echo "unknown"
        return 1
    fi
}

function show_status_replication() {
    local local_ip=$(get_local_ip)
    echo -e "\n=== Текущий статус сервера ==="
    echo "IP сервера: $local_ip"
    echo "MASTER_IP (константа): $MASTER_IP"
    echo "SLAVE_IP (константа): $SLAVE_IP"
    local role=$(get_postgres_role $local_ip)
    echo "Роль: ${role^}"
    if [[ "$role" == "master" ]]; then
        echo "Проверка состояния репликации:"
        env PGHOME=/tmp sudo -u postgres PGOPTIONS="-c search_path=pg_catalog" psql -h $MASTER_IP -c "SELECT * FROM pg_stat_replication;"
    elif [[ "$role" == "slave" ]]; then
        echo "Проверка состояния восстановления:"
        env PGHOME=/tmp sudo -u postgres PGOPTIONS="-c search_path=pg_catalog" psql -h $MASTER_IP -c "SELECT * FROM pg_stat_wal_receiver;"
    else
        echo "Роль: Не определена"
    fi
    echo -e "==============================\n"
}

function update_mail_connections() {
    local new_master="$1"
    log "Обновление параметров подключения к почтовому серверу в БД ..."
    local db_port="${CDDISK_DB_PORT:-5432}"
    local result
    result=$(echo "$CDDISK_DB_PASS" | PGPASSWORD="$CDDISK_DB_PASS" psql -h "$new_master" -U "$CDDISK_DB_USER" -p "$CDDISK_DB_PORT" -d "$CDDISK_DB_NAME" -c \
    "UPDATE public.\"EmailServers\"
        SET \"Json\" = to_jsonb(
            JSONB_SET(
                \"Json\"::jsonb,
                '{Ssh,Server}',
                '\"$MASTER_MAIL_FQDN\"'::jsonb
                )
        ),
        \"ImapServer\" = '$MASTER_MAIL_FQDN',
        \"SmtpServer\" = '$MASTER_MAIL_FQDN',
        \"PopServer\" = '$MASTER_MAIL_FQDN'
        WHERE \"CustomerId\" = (SELECT \"Id\" FROM public.\"Customers\" WHERE \"IsRoot\" = true);"
    )
    if [[ $result == "UPDATE 1" ]]; then
        log "✅ Подключение к почтовому серверу обновлено"
    else
        log "❌ Не удалось обновить подключение к почтовому серверу"
        return 1
    fi
}

function update_javamaker_connections() {
    local new_master="$1"
    local new_master_port="$2"
    log "Обновление файла /opt/r7-office/java-maker/external.properties для javamaker на новый мастер: $new_master..."

    local db_port="${CDDISK_DB_PORT:-5432}"
    local result
    result=$(echo "$CDDISK_DB_PASS" | PGPASSWORD="$CDDISK_DB_PASS" psql -h "$new_master" -U "$CDDISK_DB_USER" -p "$CDDISK_DB_PORT" -d "$CDDISK_DB_NAME" -c \
    "SELECT \"ClientId\", \"ClientSecret\" FROM public.\"AuthClients\"
        WHERE \"ApplicationKey\" = 'pages';"
    )

    CLIENT_ID=$(echo "$result" | tail -n 2 | head -n 1  | awk -F '|' '{gsub(/^[ \t]+|[ \t]+$/, "", $1); print $1}')
    CLIENT_SECRET=$(echo "$result" | tail -n 2 | head -n 1 | awk -F '|' '{gsub(/^[ \t]+|[ \t]+$/, "", $2); print $2}')

    for file in "${cs_java_configs[@]}"; do
        if [[ ! -f "$file" ]]; then
            continue
        fi

        backup_file_if_needed "$file"

        local old_line=$(grep -E "spring.datasource.url=jdbc:postgresql://"  "$file" | tr -d '\n')
        if [[ -n "$old_line" ]]; then
            sed -i -E "s|spring.datasource.url=jdbc:postgresql://[^\ ]+|spring.datasource.url=jdbc:postgresql://$new_master:$new_master_port/$JAVA_DB_NAME|" "$file"
            sed -i -E "s|spring.security.oauth2.client.registration.custom-client.client-id[^\ ]+|spring.security.oauth2.client.registration.custom-client.client-id=$CLIENT_ID|" "$file"
            sed -i -E "s|spring.security.oauth2.client.registration.custom-client.client-secret[^\ ]+|spring.security.oauth2.client.registration.custom-client.client-secret=$CLIENT_SECRET|" "$file"
            log "✅ Обновлены параметры java-maker в $file"
        fi
    done
}

function restart_services() {
    local services=("$1")
    for service in "${services[@]}"; do
        if systemctl is-active --quiet "$service"; then
            systemctl restart "$service"
            log "$service перезапущен."
        fi
    done
}

function stop_services() {
    local services=("$1")
    for service in "${services[@]}"; do
        if systemctl is-active --quiet "$service"; then
            systemctl stop "$service"
            log "$service остановлен."
        fi
    done
}

function show_current_configurations_javamaker() {
    echo -e "\n=== Текущие конфигурации Javamaker, подключение к БД ==="
    for file in "${cs_java_configs[@]}"; do
        if [[ ! -f "$file" ]]; then
            continue
        fi
        echo "  === $file ==="
        grep -E "(spring.datasource.url=jdbc:postgresql:)" "$file"
        echo ""
    done
}

function main_menu() {
    clear
    local local_ip=$(get_local_ip)
    local local_hostname=$(get_local_hostname)
    echo "=== Добро пожаловать в систему управления PostgreSQL ==="
    echo "Лог-файл: $LOG_FILE"
    echo "Текущая ОС: $DETECTED_OS (PG_DATA: $PG_DATA)"
    echo ""
    while true; do
        log "Скрипт работает на сервере ${local_hostname} с ip - ${local_ip}"
        echo "=== Меню управления PostgreSQL ==="
        echo "1. Установка параметров master"
        echo "2. Установка параметров slave (производится с удалением базы на текущей машине)"
        echo "3. Показать текущие конфиги"
        echo "4. Проверка подключения с новыми параметрами"
        echo "5. Восстановить конфигурации из .bak"
        echo "6. Перезапустить сервисы приложений"
        echo "7. Показать текущий статус сервера"
        echo "8. Остановка сервисов корпоративного сервера (холодный резерв)"
        echo "9. Выход"
        read -p "Выберите действие (1-9): " choice
        case $choice in
            1)
                switch_to_slave_as_master
                update_postfix_configs $MASTER_IP
                update_dovecot_configs $MASTER_IP
                update_mail_connections $MASTER_IP
                update_javamaker_connections $MASTER_IP $CDDISK_DB_PORT
                restart_services "java-maker.service"
                restart_mail_services
                show_status_replication
                read -p "Нажмите Enter для продолжения..."
                ;;
            2)
                switch_to_master_as_slave
                update_postfix_configs $MASTER_IP
                update_dovecot_configs $MASTER_IP
                update_javamaker_connections $MASTER_IP $CDDISK_DB_PORT
                restart_services "java-maker.service"
                restart_mail_services
                show_status_replication
                read -p "Нажмите Enter для продолжения..."
                ;;
            3)
                show_current_configurations
                show_current_configurations_postfix
                show_current_configurations_dovecot
                show_current_configurations_javamaker
                read -p "Нажмите Enter для продолжения..."
                ;;
            4)
                check_db_connection_after_change "$MASTER_IP"
                read -p "Нажмите Enter для продолжения..."
                ;;
            5)
                restore_all_configs
                read -p "Нажмите Enter для продолжения..."
                ;;
            6)
                log "Перезапуск всех сервисов..."
                supervisorctl restart all
                restart_documentserver_services
                restart_mail_services
                restart_services "java-maker.service"
                read -p "Нажмите Enter для продолжения..."
                ;;
            7)
                show_status_replication
                read -p "Нажмите Enter для продолжения..."
                ;;
            8)
                log "Остановка всех сервисов корпоративного сервера..."
                log "Состояние сервисов почтового сервера не меняется!!!"
                supervisorctl stop all
                stop_documentserver_services
                stop_services "java-maker.service"
                read -p "Нажмите Enter для продолжения..."
                ;;
            9)
                log "Выход..."
                exit 0
                ;;
            *)
                echo "Неверный выбор."
                sleep 2
                ;;
        esac
        clear
    done
}

# === MAIN ===
check_superuser
main_menu
