using System;
using System.Data;
using System.Diagnostics;
using System.IO;
using Npgsql;

public class PostgresBackupProcessor
{
    private readonly string _host = "localhost";
    private readonly string _user = "postgres";
    private readonly string _password = "Pa$$1234";
    //private readonly string _port = "5432";
    private readonly string _port = "5434";
    private readonly string _baseDb = "postgres"; // for admin tasks like drop/create

    public DataTable ProcessBackup(string backupFilePath, string query, string tempDbName = "temp_restore_db")
    {
        DropDatabase(tempDbName);
        CreateDatabase(tempDbName);
        RestoreCustomBackup(tempDbName, backupFilePath);
        DataTable result = ExecuteQuery(tempDbName, query);
        DropDatabase(tempDbName);
        return result;
    }

    private void DropDatabase(string dbName)
    {

        using (var conn = new NpgsqlConnection(GetConnectionString(_baseDb,true)))
        {
            conn.Open();
            using (var terminate = new NpgsqlCommand($@"
        SELECT pg_terminate_backend(pid)
        FROM pg_stat_activity
        WHERE datname = '{dbName}' AND pid <> pg_backend_pid();", conn))
            {
                terminate.ExecuteNonQuery();
            }
            using (var cmd = new NpgsqlCommand($@"DROP DATABASE IF EXISTS ""{dbName}"";", conn))
            {
                cmd.ExecuteNonQuery();
            }
        }
    }

    private void CreateDatabase(string dbName)
    {
        using (var conn = new NpgsqlConnection(GetConnectionString(_baseDb)))
        {
            conn.Open();
            using (var cmd = new NpgsqlCommand($@"CREATE DATABASE ""{dbName}"";", conn))
            {
                cmd.ExecuteNonQuery();
            }
        }
    }
    public static string GetPGProgess(string pgProcessName)
    {
        return System.IO.Path.Combine(Mindrockets.Helpers.Config.Instance.GetValueFromConfig("pgPath", @"C:\Program Files\PostgreSQL\15\bin"), pgProcessName);
    
    }
    private void RestoreCustomBackup(string dbName, string backupFilePath)
    {
        var psi = new ProcessStartInfo
        {
            FileName = GetPGProgess("pg_restore.exe"),
            Arguments = $"-U {_user} -h {_host} -p {_port} -d {dbName} \"{backupFilePath}\"",
            UseShellExecute = false,
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            CreateNoWindow = true
        };

        psi.EnvironmentVariables["PGPASSWORD"] = _password;

        using (var process = Process.Start(psi))
        {
            string output = process.StandardOutput.ReadToEnd();
            string error = process.StandardError.ReadToEnd();
            process.WaitForExit();

            if (process.ExitCode != 0)
            {
                throw new Exception("pg_restore failed:\n" + error);
            }
        }
    }

    private DataTable ExecuteQuery(string dbName, string query)
    {
        var dt = new DataTable();
        using (var conn = new NpgsqlConnection(GetConnectionString(dbName)))
        {
            conn.Open();
            using (var cmd = new NpgsqlCommand(query, conn))
            using (var reader = cmd.ExecuteReader())
            {
                dt.Load(reader);
            }
        }
        return dt;
    }

    private string GetConnectionString(string dbName, bool admin = false)
    {
        string baseConn = $"Host={_host};Port={_port};Username={_user};Password={_password};Database={dbName};";

        if (admin)
        {
            // Disable multiplexing (pipelining) for DROP DATABASE
            baseConn += "Multiplexing=false;";
        }

        return baseConn;
    }
}
