#!/bin/bash

YELLOW='\033[0;33m'
GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m'

spinner() {
    local pid=$1
    local delay=0.1
    local spinstr='|/-\'
    while kill -0 $pid 2>/dev/null; do
        local temp=${spinstr#?}
        printf " ${YELLOW}[%c]${NC}  " "$spinstr"
        spinstr=$temp${spinstr%"$temp"}
        sleep $delay
        printf "\b\b\b\b\b\b"
    done
    printf "     \b\b\b\b\b"
}

dump_clickhouse_db() {

    BACKUP_ROOT_DIR="/backups"
    rm -rf "$BACKUP_ROOT_DIR"
    mkdir -p "$BACKUP_ROOT_DIR"

    CONFIG_DIR="/etc/clickhouse-server/config.d"
    CONFIG_FILE="$CONFIG_DIR/backup_disk.xml"

    mkdir -p "$CONFIG_DIR"

    # https://clickhouse.com/docs/ru/operations/backup/disk
    XML_CONTENT='<?xml version="1.0"?>
    <clickhouse>
        <storage_configuration>
            <disks>
                <backups>
                    <type>local</type>
                    <path>'"$BACKUP_ROOT_DIR/"'</path>
                </backups>
            </disks>
        </storage_configuration>
        <backups>
            <allowed_disk>backups</allowed_disk>
            <allowed_path>'"$BACKUP_ROOT_DIR/"'</allowed_path>
        </backups>
    </clickhouse>'

    echo "$XML_CONTENT" | sudo tee "$CONFIG_FILE" > /dev/null

    CLICKHOUSE_USER="clickhouse"
    sudo chown -R "$CLICKHOUSE_USER:$CLICKHOUSE_USER" "$BACKUP_ROOT_DIR" || \
    echo "Warning: Could not set ownership to $CLICKHOUSE_USER. Ensure ClickHouse can write to $BACKUP_ROOT_DIR."

    python3 src/py_utils/service.py clickhouse-server restart
    if [ $? -eq 0 ]
    then
        echo "clickhouse restarted"
    else
        exit 1
    fi

    clickhouse-client --host=$host --port=$ch_port --user=default --password=$ch_def_user_password --query="SELECT name FROM system.disks WHERE name='backups';"
    if [ $? -ne 0 ]; then
        echo "Disk 'backups' is not available. Check configuration."
        exit 1
    fi

    echo "Starting backup..."
    clickhouse-client --host=$host --port=$ch_port --user=default --password=$ch_def_user_password --query="BACKUP DATABASE $ch_db_name_from TO Disk('backups', 'ch_backup.zip');"

    if [ $? -eq 0 ]; then
        echo "Backup completed successfully."
    else
        echo "Backup failed."
        exit 1
    fi
}

dump_table() {
    local table_name="$1"
    local output_file="$2"

    echo "Table $table_name is dumping..."

    # pre-data — структура таблиц, типы, функции, без ограничений (но с DEFAULT, NOT NULL, типами)
    # data — данные (INSERT)
    PGPASSWORD="$password" pg_dump --format=c --section=pre-data --section=data -t "$table_name" "$db_name" -U "$user" -h "$host" -p "$port" > "$output_file" 2>/dev/null &
    local dump_pid=$!

    spinner "$dump_pid"
    wait "$dump_pid"

    if [ $? -eq 0 ]; then
        echo -e "${GREEN}Table $table_name was dumped successfully${NC}"
    else
        echo -e "${RED}Error dumping table $table_name${NC}"
        exit 1
    fi
}

# для таблиц без возможности навесить ограничения (post-data) при дальнейшем запуске сервисов (live, analyzer)
dump_table_with_constraints() {
    local table_name="$1"
    local output_file="$2"

    echo "Table $table_name is dumping..."

    PGPASSWORD="$password" pg_dump --format=c -t "$table_name" "$db_name" -U "$user" -h "$host" -p "$port" > "$output_file" 2>/dev/null &
    local dump_pid=$!

    spinner "$dump_pid"
    wait "$dump_pid"

    if [ $? -eq 0 ]; then
        echo -e "${GREEN}Table $table_name was dumped successfully${NC}"
    else
        echo -e "${RED}Error dumping table $table_name${NC}"
        exit 1
    fi
}

dump_table_with_psql() {
    local table_name="$1"
    local output_file="$2"
    local custom_req="${3:-}" # optoinal param

    echo "Table $table_name is dumping..."

    if [ -n "$custom_req" ]
    then
        PGPASSWORD="$password" psql -U "$user" -d "$db_name" -t -A -F"," -c "$custom_req" -h "$host" -p "$port" > "$output_file" &
    else
        PGPASSWORD="$password" psql -U "$user" -d "$db_name" -t -A -F"," -c "SELECT * FROM $table_name;" -h "$host" -p "$port" > "$output_file" &
    fi

    local psql_pid=$!

    spinner "$psql_pid"
    wait "$psql_pid"

    if [ $? -eq 0 ]; then
        echo -e "${GREEN}Table $table_name was dumped successfully${NC}"
    else
        echo -e "${RED}Error dumping table $table_name via psql${NC}"
        exit 1
    fi
}
dump_table_with_psql_copy() {
    local table_name="$1"
    local output_file="$2"
    local custom_query="$3"

    echo "Table $table_name is dumping with copy to stdout..."

    local temp_script=$(mktemp)
    cat <<EOF > "$temp_script"
COPY (
$custom_query
) TO STDOUT WITH CSV;
EOF

    PGPASSWORD="$password" psql -U "$user" -d "$db_name" -h "$host" -p "$port" -f "$temp_script" > "$output_file" &

    local psql_pid=$!

    spinner "$psql_pid"
    wait "$psql_pid"
    local exit_code=$?

    rm "$temp_script"

    if [ $exit_code -eq 0 ]; then
        echo -e "${GREEN}Table $table_name was dumped successfully${NC}"
    else
        echo -e "${RED}Error dumping table $table_name via psql${NC}"
        exit 1
    fi
}
host=$1
user=$2
password=$3
db_name=$4
port=$5
ch_def_user_password=$6
ch_db_name_from=$7
ch_port=$8
license=$9

rm -rf dumps
mkdir dumps -p

faces_dump_req="SELECT
    evi.faces.uuid,
    evi.faces.data,
    evi.guest.photo AS guest_photo,
    evi.worker.photo AS worker_photo
    FROM evi.faces
    LEFT JOIN evi.guest ON uuid = evi.guest.guest_id
    LEFT JOIN evi.worker ON uuid = evi.worker.worker_id
    WHERE evi.guest.photo IS NOT NULL OR evi.worker.photo IS NOT NULL;"
dump_table_with_psql "evi.faces" "./dumps/faces.csv" "$faces_dump_req"

dump_table "evi.access_level_controller" "./dumps/access_level_controller.sql"
dump_table_with_constraints "evi.access_level_worker" "./dumps/access_level_worker.sql"
dump_table "evi.access_pattern" "./dumps/access_pattern.sql"
dump_table "evi.access_pattern_relay" "./dumps/access_pattern_relay.sql"
dump_table_with_psql "evi.access_views" "./dumps/access_views.csv"
dump_table_with_constraints "evi.analytics_schedule" "./dumps/analytics_schedule.sql"
dump_table "evi.apikey" "./dumps/apikey.sql"
dump_table_with_constraints "evi.calendar" "./dumps/calendar.sql"
dump_table "evi.calendar_dates" "./dumps/calendar_dates.sql"
dump_table "evi.calendar_day_time" "./dumps/calendar_day_time.sql"
dump_table_with_psql "evi.camera" "./dumps/camera.csv"
dump_table_with_constraints "evi.camera_archive_schedule" "./dumps/camera_archive_schedule.sql"
dump_table_with_constraints "evi.camera_detection_schedule" "./dumps/camera_detection_schedule.sql"
dump_table_with_constraints "evi.camera_stream" "./dumps/camera_stream.sql"
dump_table_with_psql "evi.car" "./dumps/car.csv"
dump_table "evi.card" "./dumps/card.sql"
dump_table_with_constraints "evi.cell_views" "./dumps/cell_views.sql"
dump_table_with_psql "evi.controller" "./dumps/controller.csv"
dump_table "evi.controller_cached" "./dumps/controller_cached.sql"
dump_table "evi.critical_event" "./dumps/critical_event.sql"
dump_table "evi.discrete_input" "./dumps/discrete_input.sql"
dump_table_with_psql "evi.divisions" "./dumps/division.csv"
dump_table "evi.entity_plan_position" "./dumps/entity_plan_position.sql"
dump_table "evi.firmware" "./dumps/firmware.sql"

guests_dump_req="SELECT
    guest_id,
    last_name,
    first_name,
    patronymic,
    organization,
    CONCAT('[', REPLACE(comment, '\"', '\"\"'), ']') AS comment,
    mobile,
    email,
    birth_date,
    photo,
    analytics
FROM evi.guest
EOF"
dump_table_with_psql_copy "evi.guest" "./dumps/guest.csv" "$guests_dump_req"

dump_table "evi.guest_pass_event" "./dumps/guest_pass_event.sql"
dump_table "evi.guest_access_pattern" "./dumps/guest_access_pattern.sql"
dump_table "evi.interactive_plan" "./dumps/interactive_plan.sql"

if [ $license == "true" ] || [ $license == 0 ]; then
    dump_table "evi.license_params" "./dumps/license_params.sql"
fi

dump_table "evi.lines" "./dumps/lines.sql"
dump_table_with_constraints "evi.location" "./dumps/location.sql"
dump_table "evi.masks" "./dumps/masks.sql"
dump_table "evi.maskspoints" "./dumps/maskspoints.sql"
dump_table "evi.not_acked_event_cache" "./dumps/not_acked_event_cache.sql"
dump_table_with_psql "evi.organizations" "./dumps/organization.csv"
dump_table_with_psql "evi.pass_event" "./dumps/pass_event.csv"
dump_table "evi.pass_info" "./dumps/pass_info.sql"
dump_table_with_psql "evi.photo" "./dumps/photo.csv"
dump_table_with_psql "evi.positions" "./dumps/position.csv"
dump_table "evi.reader" "./dumps/reader.sql"
dump_table "evi.relay" "./dumps/relay.sql"
dump_table "evi.schedule" "./dumps/schedule.sql"
dump_table "evi.settings" "./dumps/settings.sql"
dump_table "evi.stream_params" "./dumps/stream_params.sql"
dump_table_with_constraints "evi.streams" "./dumps/streams.sql"

trigger_dump_req="SELECT
                    evi.camera_analytics_triggers.trigger_id,
                    evi.camera_analytics_triggers.name,
                    evi.camera_analytics_triggers.active,
                    evi.camera_analytics_triggers.type,
                    evi.camera_analytics_triggers.model,
                    evi.camera_analytics_triggers.params,
                    evi.camera_analytics_triggers.camera AS source_camera,
                    evi.camera_analytics_control_object.state AS control_object_state,
                    evi.camera_analytics_control_object.relay AS control_object,
                    evi.camera_analytics_control_object.trigger AS control_object_trigger,
                    evi.camera_analytics_record_archive.trigger AS record_archive_trigger,
                    evi.camera_analytics_record_archive.gap AS record_camera_gap,
                    evi.camera_analytics_record_archive.camera AS record_camera
                FROM evi.camera_analytics_triggers
                LEFT JOIN evi.camera_analytics_control_object ON trigger_id = evi.camera_analytics_control_object.trigger
                LEFT JOIN evi.camera_analytics_record_archive ON trigger_id = evi.camera_analytics_record_archive.trigger;"

dump_table_with_psql "evi.camera_analytics_triggers" "./dumps/triggers.csv" "$trigger_dump_req"

dump_table "evi.update_plan" "./dumps/update_plan.sql"
dump_table_with_psql "evi.users" "./dumps/users.csv"
dump_table_with_constraints "evi.views" "./dumps/views.sql"
dump_table "evi.visit" "./dumps/visit.sql"

visit_dump_req="SELECT
    evi.visit.visit_id,
    TO_CHAR(evi.visit.date_start, 'DD.MM.YYYY') AS date_start,
    TO_CHAR(evi.visit.date_start, 'HH24:MI') AS time_start,
    TO_CHAR(evi.visit.date_end, 'DD.MM.YYYY') AS date_end,
    TO_CHAR(evi.visit.date_end, 'HH24:MI') AS time_end
    FROM evi.visit
    WHERE evi.visit.status != 'not active';"
dump_table_with_psql "evi.visit2" "./dumps/visit2.csv" "$visit_dump_req"

dump_table "evi.visit_card" "./dumps/visit_card.sql"
dump_table "evi.visit_card_history" "./dumps/visit_card_history.sql"
dump_table_with_psql "evi.visit_purposes" "./dumps/visit_purposes.csv"
dump_table_with_psql "evi.worker" "./dumps/worker.csv"
dump_table "evi.worker_access_pattern" "./dumps/worker_access_pattern.sql"
dump_table "evi.worker_calendar" "./dumps/worker_calendar.sql"
dump_table_with_psql "evi.worker_car" "./dumps/worker_car.csv"
dump_table "evi.worker_card" "./dumps/worker_card.sql"
dump_table "evi.worker_urv" "./dumps/worker_urv.sql"
dump_table "evi.zones" "./dumps/zones.sql"
dump_table "evi.zonepoints" "./dumps/zonepoints.sql"

dump_clickhouse_db

exit 0
