using Microsoft.IdentityModel.Tokens;
using Microsoft.Win32;
using System.Data;
using System.Diagnostics;
using System.Net.Sockets;
using System.Text;
using Universal;

namespace Test;

internal class Program
{
    static void Main()
    {
        CompressTest test = new();
        test.Test();

        //DBTest test = new();
        //test.Initialize();
        //test.Test();
        //test.TestSystem();
        //test.TestOthers();
        //test.TestRaw();

        //ProcessTest processTest = new();
        //processTest.Initialize();
        //processTest.BackUp("10.4.6.48", 5432, "postgres", "123456", "D://source_db_dump.custom", "tin01_db");
        //processTest.BackUpSingleTable("localhost", 5432, "postgres", "123456", "D://source_db_dump.custom", "FROMTIN", "20250630.PM1");
        //processTest.BackUpByDateTime("localhost", 5432, "postgres", "123456", "D://source_db_dump.custom", "FROMTIN", "20250630");
        //processTest.Restore("localhost", 5432, "postgres", "123456", "D://source_db_dump.custom", "DBTestTIN");
    }
}

internal class ProcessTest
{
    //HKEY_LOCAL_MACHINE\SOFTWARE\PostgreSQL\Installations\postgresql*
    private string? _binPath;
    private string? pg_dump;
    private string? pg_restore;

    public bool Initialize()
    {
        RegistryKey key = Registry.LocalMachine;
        key = key.OpenSubKey("SOFTWARE\\PostgreSQL\\Installations");

        if (key is null)
            key = key.OpenSubKey("SOFTWARE\\WOW6432Node\\PostgreSQL\\Installations");

        if (key is null)
            return false;

        if (key.GetSubKeyNames().FirstOrDefault(t => t.Contains("postgresql")) is not string nextKey)
            return false;

        key = key.OpenSubKey(nextKey);
        if (key.GetValue("Base Directory") is not string path)
            return false;

        this.pg_dump = Path.Combine(path, "bin", "pg_dump.exe");
        this.pg_restore = Path.Combine(path, "bin", "pg_restore.exe");

        return true;
    }

    public bool BackUp(string serverAddress, int port, string userName, string password, string savePath, string dbName)
    {
        if (string.IsNullOrEmpty(this.pg_dump))
            return false;

        Process process = new Process();
        process.StartInfo.Environment.Add("PGPASSWORD", password);
        process.StartInfo.FileName = this.pg_dump;
        process.StartInfo.Arguments = string.Format($"-h {serverAddress} -p {port} -U {userName} -F c -v -f \"{savePath}\" {dbName}");
        process.StartInfo.CreateNoWindow = false;
        process.Start();
        process.WaitForExit();
        return true;
    }

    public bool Restore(string serverAddress, int port, string userName, string password, string savePath, string dbName)
    {
        if (string.IsNullOrEmpty(this.pg_restore))
            return false;

        Process process = new Process();
        process.StartInfo.Environment.Add("PGPASSWORD", password);
        process.StartInfo.FileName = this.pg_restore;
        process.StartInfo.Arguments = string.Format($"-h {serverAddress} -p {port} -U {userName} -v -d {dbName} --clean \"{savePath}\"");
        process.StartInfo.CreateNoWindow = false;
        process.Start();
        process.WaitForExit();

        return true;
    }

    public bool BackUpSingleTable(string serverAddress, int port, string userName, string password, string savePath, string dbName, string tableName)
    {
        if (string.IsNullOrEmpty(this.pg_dump))
            return false;

        Process process = new Process();
        process.StartInfo.RedirectStandardOutput = true;

        process.StartInfo.StandardOutputEncoding = Encoding.UTF8;
        process.StartInfo.Environment.Add("PGPASSWORD", password);
        process.StartInfo.FileName = this.pg_dump;
        process.StartInfo.Arguments = string.Format($"-h {serverAddress} -p {port} -U {userName} -F c -v -f \"{savePath}\" --table \"{tableName}\" {dbName}");
        process.StartInfo.CreateNoWindow = false;
        process.Start();
        process.WaitForExit();
        return true;
    }

    public bool BackUpByDateTime(string serverAddress, int port, string userName, string password, string savePath, string dbName, string time)
    {
        if (string.IsNullOrEmpty(this.pg_dump))
            return false;

        Process process = new Process();
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.StandardOutputEncoding = Encoding.UTF8;
        process.StartInfo.Environment.Add("PGPASSWORD", password);
        process.StartInfo.FileName = this.pg_dump;
        process.StartInfo.Arguments = string.Format($"-h {serverAddress} -p {port} -U {userName} -F c -v -f \"{savePath}\" --table {time}* {dbName}");
        process.StartInfo.CreateNoWindow = false;
        process.Start();
        process.WaitForExit();
        return true;
    }

}

internal class CompressTest
{
    public void Test()
    {
        using MemoryStream stream = new();

        Compressor.CompressZipFileDirectory(new(@"E:\Recipes"), stream);
        Console.WriteLine(this.SplitSpan(stream, CallBack) ? "Send Success" : "Send Failed");
    }

    private bool CallBack(byte[] input, int current, int total)
    {
        Console.WriteLine($"{input.Length} {current} / {total}");
        return true;
    }

    private bool SplitSpan(MemoryStream stream, Func<byte[], int, int, bool> callBack, int packLength = 4096)
    {
        if (packLength < 256)
            return false;

        Span<byte> t = stream.ToArray();
        int count = t.Length / packLength;

        Span<byte> ts;
        for (int i = 0; i <= count; i++)
        {
            if (i == count)
            {
                ts = t.Slice(i * packLength);
                if (callBack?.Invoke(ts.ToArray(), i, count) != true)
                    return false;
                break;
            }
            ts = t.Slice(i * packLength, packLength);
            if (callBack?.Invoke(ts.ToArray(), i, count) != true)
                return false;
        }

        return true;
    }

}