#!/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"
}

restore_clickhouse_db() {
    echo "Restoring clickhouse db from dump 'ch_backup.zip'..."
    BACKUP_ROOT_DIR="backups"
    if [ ! "/$BACKUP_ROOT_DIR" ]; then
        echo -e "${RED}Error:${NC} Backup file $BACKUP_ROOT_DIR does not exist."
        exit 1
    fi

    clickhouse-client --host=$host --port=$ch_port --user=$user --password=$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

    local query="RESTORE DATABASE $ch_db_name_from AS $ch_db_name_to FROM Disk ('$BACKUP_ROOT_DIR', 'ch_backup.zip')"
    clickhouse-client --host=$host --port=$ch_port --user=$user --password=$password --query="$query"

    if [ $? -eq 0 ]; then
        echo -e "${GREEN}Restore clickhouse completed successfully.${NC}"
    else
        echo -e "${RED}Restore failed.${NC}"
        exit 1
    fi
}

run_with_spinner() {
    local full_command="$*"

    echo "Executing: ${full_command}..."

    "$@" &
    local cmd_pid=$!

    spinner "$cmd_pid"
    wait "$cmd_pid"

    if [ $? -eq 0 ]; then
        echo -e "${GREEN}Command successed: ${full_command}${NC}"
    else
        echo -e "${RED}Command error: ${full_command}${NC}"
        exit 1
    fi
}

restore_dump() {
    local dump_file="$1"

    local base_name=$(basename "$dump_file")
    local table_name="${base_name%.sql}"

    if [ ! -s "$dump_file" ]; then
        echo "Skipping restoring '$table_name': '$dump_file' is empty or does not exist"
        return 1
    fi

    echo "Restoring table '$table_name' from dump '$dump_file'..."

    if [ -n "$psql_docker_name" ]; then
        local container_path="/tmp/$(basename "$dump_file")"
        (
            docker cp "$dump_file" "$psql_docker_name:$container_path" &&
            docker exec -e PGPASSWORD="$password" "$psql_docker_name" \
                pg_restore -d "$db_name" -U "$user" "$container_path"
            restore_rc=$?
            docker exec "$psql_docker_name" rm -f "$container_path" 2>/dev/null
            exit $restore_rc
        ) &
    else
        PGPASSWORD="$password" pg_restore -d "$db_name" -U "$user" -h "$host" -p "$psql_port" "$dump_file" &
    fi
    local restore_pid=$!

    spinner "$restore_pid"
    wait "$restore_pid"

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

restore_sql_file() {
    local sql_file="$1"

    local base_name=$(basename "$sql_file")
    local table_name="${base_name%.sql}"

    echo "Restoring table '$table_name' from sql file '$sql_file'..."

    if [ ! -s "$sql_file" ]; then
        echo "Skipping restoring '$table_name': '$sql_file' is empty or does not exist"
        return 1
    fi

    run_psql_stdin -d "$db_name" -1 --single-transaction < "$sql_file" &
    local psql_pid=$!

    spinner "$psql_pid"
    wait "$psql_pid"

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

restore_csv_file_clickhouse() {
    local csv_file="$1"

    local base_name=$(basename "$csv_file")
    local table_name="${base_name%.csv}"

    echo "Restoring table '$table_name' from csv file '$csv_file'..."

    if [ ! -s "$csv_file" ]; then
        echo "Skipping restoring '$table_name': '$csv_file' is empty or does not exist"
        return 1
    fi

    echo -e "clickhouse-client --host=$host --port=$ch_port --user=default --password=$ch_def_user_password --database=$ch_db_name_to --query="INSERT INTO $table_name FORMAT CSV" < $csv_file"
    clickhouse-client --host=$host --port=$ch_port --user=default --password=$ch_def_user_password --database=$ch_db_name_to --query="INSERT INTO $table_name FORMAT CSV" < $csv_file &
    local ch_pid=$!

    spinner "$ch_pid"
    wait "$ch_pid"

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

host=$1
user=$2
password=$3
psql_docker_name=$4
db_name=$5
psql_port=$6
ch_def_user_password=$7
ch_db_name_from=$8
ch_db_name_to=$9
ch_port=${10}
license=${11}

# Wrapper: runs psql either directly on the host or inside a Docker container.
# Usage: run_psql <psql_args...>  (without -U/-h/-p — handled here)
run_psql() {
    if [ -n "$psql_docker_name" ]; then
        docker exec -e PGPASSWORD="$password" "$psql_docker_name" psql -U "$user" "$@"
    else
        PGPASSWORD="$password" psql -U "$user" -h "$host" -p "$psql_port" "$@"
    fi
}

# Same as run_psql, but keeps stdin attached (docker exec -i) so a local script/file
# can be piped in with `< file` regardless of docker vs direct mode.
run_psql_stdin() {
    if [ -n "$psql_docker_name" ]; then
        docker exec -i -e PGPASSWORD="$password" "$psql_docker_name" psql -U "$user" "$@"
    else
        PGPASSWORD="$password" psql -U "$user" -h "$host" -p "$psql_port" "$@"
    fi
}

if [ "$host" == "0.0.0.0" ] || [ "$host" == "localhost" ]
then
    python3 src/py_utils/service.py evi-scud stop
    if [ $? -ne 0 ]
    then
        exit 1
    fi

    python3 src/py_utils/service.py evi-core stop
    if [ $? -ne 0 ]
    then
        exit 1
    fi

    python3 src/py_utils/service.py evi-live stop
    if [ $? -ne 0 ]
    then
        exit 1
    fi

    python3 src/py_utils/service.py evi-analyzer stop
    if [ $? -ne 0 ]
    then
        exit 1
    fi

    python3 src/py_utils/docker.py evi-analytics stop
    if [ $? -ne 0 ]
    then
        exit 1
    fi

    python3 src/py_utils/service.py evi-archive stop
    if [ $? -ne 0 ]
    then
        exit 1
    fi

    if [ -n "$psql_docker_name" ]; then
        python3 src/py_utils/docker.py "$psql_docker_name" restart
    else
        python3 src/py_utils/service.py postgresql restart
    fi
    if [ $? -ne 0 ]
    then
        exit 1
    fi

    python3 src/py_utils/service.py clickhouse-server restart
    if [ $? -ne 0 ]
    then
        exit 1
    fi

    if [ -n "$psql_docker_name" ]; then
        run_psql -d postgres -c "create user $user;"
        run_psql -d postgres -c "ALTER USER $user WITH PASSWORD '$password';"
        run_psql -d postgres -c "ALTER USER $user WITH SUPERUSER;"

        run_psql -d postgres -c "DROP DATABASE IF EXISTS $db_name;"
        run_psql -d postgres -c "CREATE DATABASE $db_name;"
    else
        su postgres -c "psql -c \"create user $user;\""
        su postgres -c "psql -c \"ALTER USER $user WITH PASSWORD '$password';\""
        su postgres -c "psql -c \"ALTER USER $user WITH SUPERUSER;\""

        su postgres -c "psql -c \"DROP DATABASE IF EXISTS $db_name;\""
        su postgres -c "psql -c \"CREATE DATABASE $db_name;\""
    fi

    echo "PostgreSQL configured"

    clickhouse-client --host=$host --port=$ch_port --user=default --password=$ch_def_user_password --query="CREATE USER IF NOT EXISTS $user IDENTIFIED WITH sha256_password BY '$password'" --query="GRANT CURRENT GRANTS on *.* TO $user WITH GRANT OPTION"
    clickhouse-client --host=$host --port=$ch_port --user=default --password=$ch_def_user_password --query="DROP DATABASE IF EXISTS $ch_db_name_to"
    clickhouse-client --host=$host --port=$ch_port --user=$user --password=$password --query="CREATE DATABASE IF NOT EXISTS $ch_db_name_to"
    clickhouse-client --host=$host --port=$ch_port --user=$user --password=$password --query="CREATE TABLE IF NOT EXISTS $ch_db_name_to.operational_events (\`id\` UUID, \`timestamp\` DateTime64(6), \`code\` Int16, \`level\` Int16, \`controller\` String, \`location\` String, \`user\` String, \`relay\` String, \`di\` String, \`camera\` String, \`cameraStream\` String, \`card\` String, \`car\` String, \`worker\` String, \`guest\` String, \`prevCard\` String, \`prevWorker\` String, \`prevGuest\` String, \`prevDi\` String, \`service\` String, \`updateTask\` String, \`faceList\` String, \`carList\` String, \`face\` String, \`object\` String, \`directionZone\` String, \`crossLine\` String) ENGINE = ReplacingMergeTree PARTITION BY toYYYYMM(timestamp) ORDER BY (timestamp, code, level, controller, location, user, relay, di, camera, cameraStream, card, car, worker, guest, prevCard, prevWorker, prevGuest, prevDi, service, updateTask, faceList, carList, face, object, directionZone, crossLine) SETTINGS index_granularity = 8192"

    echo "Clickhouse configured"
fi

run_psql -X -d "$db_name" -c "CREATE SCHEMA IF NOT EXISTS evi;"

rm -rf restores
mkdir restores -p

run_with_spinner python3 src/py_utils/preconf.py ./restores/preconf.sql
restore_sql_file "./restores/preconf.sql"

restore_dump "./dumps/access_level_controller.sql"
restore_dump "./dumps/access_level_worker.sql"
restore_dump "./dumps/access_pattern.sql"
restore_dump "./dumps/access_pattern_relay.sql"
restore_dump "./dumps/location.sql"
restore_dump "./dumps/md_profile.sql"

run_with_spinner python3 src/py_utils/gen_camera.py ./dumps/camera.csv ./restores/camera.sql # ссылается на evi.location и evi.md_profile
restore_sql_file "./restores/camera.sql"

restore_dump "./dumps/streams.sql" # ссылается на evi.camera
restore_dump "./dumps/analytics_schedule.sql" # ссылается на evi.streams
restore_dump "./dumps/apikey.sql"
restore_dump "./dumps/calendar.sql"
restore_dump "./dumps/calendar_dates.sql"
restore_dump "./dumps/calendar_day_time.sql"
restore_dump "./dumps/camera_analytics_photo_list.sql"
restore_dump "./dumps/triggers.sql"
restore_dump "./dumps/camera_analytics_vehicle_list.sql"
restore_dump "./dumps/camera_archive_schedule.sql"
restore_dump "./dumps/camera_detection_schedule.sql"
restore_dump "./dumps/camera_stream.sql"

run_with_spinner python3 src/py_utils/gen_car_dump.py ./dumps/car.csv ./restores/car.sql
restore_sql_file "./restores/car.sql"

restore_dump "./dumps/card.sql"
restore_dump "./dumps/controller.sql"
restore_dump "./dumps/controller_cached.sql"

run_with_spinner python3 src/py_utils/gen_critical_event.py ./dumps/critical_event.csv ./restores/critical_event.sql
restore_sql_file "./restores/critical_event.sql"

restore_dump "./dumps/discrete_input.sql"
restore_dump "./dumps/division.sql"
restore_dump "./dumps/entity_plan_position.sql"
restore_dump "./dumps/faces.sql"
restore_dump "./dumps/firmware.sql"
restore_dump "./dumps/guest.sql"
restore_dump "./dumps/guest_access_pattern.sql"
restore_dump "./dumps/guest_car.sql"
restore_dump "./dumps/guest_pass_event.sql"
restore_dump "./dumps/guest_photo.sql"
restore_dump "./dumps/interactive_plan.sql"

if [ "$license" == "true" ] || [ "$license" == 1 ]; then
    restore_dump "./dumps/license_params.sql"
fi

restore_dump "./dumps/lines.sql"
restore_dump "./dumps/masks.sql"
restore_dump "./dumps/maskspoints.sql"
restore_dump "./dumps/not_acked_event_cache.sql"
restore_dump "./dumps/object_list.sql"
restore_dump "./dumps/object_list_car.sql"
restore_dump "./dumps/object_list_photo.sql"
restore_dump "./dumps/organization.sql"
restore_dump "./dumps/other_person.sql"
restore_dump "./dumps/other_person_car.sql"
restore_dump "./dumps/other_person_photo.sql"
restore_dump "./dumps/pass_event.sql"
restore_dump "./dumps/pass_info.sql"

run_with_spinner python3 src/py_utils/gen_photo_dump.py ./dumps/photo.csv ./restores/photo
for file in ./restores/photo_*.sql; do
    restore_sql_file "$file"
done

restore_dump "./dumps/position.sql"
restore_dump "./dumps/reader.sql"
restore_dump "./dumps/relay.sql"
restore_dump "./dumps/schedule.sql"
restore_dump "./dumps/settings.sql"
restore_dump "./dumps/stream_params.sql"
restore_dump "./dumps/trigger_user_link.sql"
restore_dump "./dumps/update_plan.sql"

run_with_spinner python3 src/py_utils/gen_user_and_role_dump.py ./dumps/user.csv ./restores/user.sql
restore_sql_file "./restores/user.sql"

run_with_spinner python3 src/py_utils/gen_views_and_cell_views.py ./dumps/access_views.csv ./dumps/views.csv ./dumps/cell_views.csv ./dumps/user_role.csv ./restores/views_and_cell_views.sql # требуются данные views, cell_views, user_id и role из user
restore_sql_file "./restores/views_and_cell_views.sql"

restore_dump "./dumps/visit.sql"
restore_dump "./dumps/visit_card.sql"
restore_dump "./dumps/visit_card_history.sql"
restore_dump "./dumps/visit_purpose.sql"
restore_dump "./dumps/worker.sql"
restore_dump "./dumps/worker_access_pattern.sql"
restore_dump "./dumps/worker_calendar.sql"
restore_dump "./dumps/worker_car.sql"
restore_dump "./dumps/worker_card.sql"
restore_dump "./dumps/worker_photo.sql"
restore_dump "./dumps/worker_urv.sql"
restore_dump "./dumps/zones.sql"
restore_dump "./dumps/zonepoints.sql"


dump_file="./dumps/operational_events.csv"
if [ ! -s "$dump_file" ]; then
    echo "Skipping restoring 'operational_events': '$dump_file' is empty or does not exist"
else
    run_with_spinner python3 src/py_utils/gen_operational_event_dump.py ./dumps/operational_events.csv ./restores/operational_events.csv
    restore_csv_file_clickhouse "./restores/operational_events.csv"
fi

exit 0
