using File_Watcher.Models;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;

namespace File_Watcher.Helpers;

internal static partial class HelperTCP
{

    private record Record(BinaryReader BinaryReader,
                          BinaryWriter BinaryWriter,
                          NetworkStream NetworkStream);

    private static long _LastWrite;
    private static Record? _Record;
    private static TcpListener? _TcpListener;
    private static readonly object _Lock = new();

    private static void OnAccept(IAsyncResult asyncResult)
    {
        if (_TcpListener is null)
            throw new NullReferenceException(nameof(_TcpListener));
        lock (_Lock)
        {
            TcpClient tcpClient = _TcpListener.EndAcceptTcpClient(asyncResult);
            NetworkStream networkStream = tcpClient.GetStream();
            _Record = new(new(networkStream), new(networkStream), networkStream);
        }
    }

    private static string ConvertSourceFileToPdf(string ghostPCLFileName, string reportFullPath)
    {
        string result = Path.ChangeExtension(reportFullPath, ".pdf");
        if (!File.Exists(result))
        {
            //string arguments = string.Concat("-i \"", sourceFile, "\" -o \"", result, "\"");
            string arguments = string.Concat("-dSAFER -dBATCH -dNOPAUSE -sOutputFile=\"", result, "\" -sDEVICE=pdfwrite \"", reportFullPath, "\"");
            //Process process = Process.Start(configData.LincPDFCFileName, arguments);
            Process process = Process.Start(ghostPCLFileName, arguments);
            _ = process.WaitForExit(30000);
            if (!File.Exists(result))
                throw new Exception("PDF file wasn't created");
        }
        return result;
    }

    private static void BeginAcceptTcpClient()
    {
        if (_TcpListener is null)
            throw new NullReferenceException(nameof(_TcpListener));
        _ = _TcpListener.BeginAcceptTcpClient(OnAccept, null);
    }

    private static void ReadFiles(TransmissionControlProtocolConfiguration transmissionControlProtocolConfiguration)
    {
        List<byte> bytes = [];
        // byte nullByte = Convert.ToByte('\0');
        string[] files = Directory.GetFiles(transmissionControlProtocolConfiguration.Destination, $"{transmissionControlProtocolConfiguration.IPAddress}-*.raw", SearchOption.TopDirectoryOnly);
        foreach (string file in files)
        {
            foreach (byte @byte in File.ReadAllBytes(file))
            {
                // if (@byte.Equals(nullByte))
                //     continue;
                bytes.Add(@byte);
            }
        }
        if (bytes.Count > 0)
        {
            string bytesFile = Path.Combine(transmissionControlProtocolConfiguration.Destination, $"{transmissionControlProtocolConfiguration.IPAddress}-{DateTime.Now.Ticks}.pcl");
            File.WriteAllBytes(bytesFile, bytes.ToArray());
            string ghostPCLFileName = Path.Combine(AppContext.BaseDirectory, "gpcl6win64.exe");
            if (!File.Exists(ghostPCLFileName))
                throw new Exception("Ghost PCL FileName doesn't Exist!");
            string sourceFileNamePdf = ConvertSourceFileToPdf(ghostPCLFileName, bytesFile);
            if (string.IsNullOrEmpty(sourceFileNamePdf))
                throw new Exception("Ghost PCL FileName doesn't Exist!");
        }
    }

    private static void CreateClient(AppSettings appSettings, ILogger<Worker> logger)
    {
        logger.LogDebug(appSettings.TransmissionControlProtocolConfiguration.IPAddress);
        TcpClient tcpClient = new(appSettings.TransmissionControlProtocolConfiguration.IPAddress, appSettings.TransmissionControlProtocolConfiguration.Port);
        NetworkStream networkStream = tcpClient.GetStream();
        _Record = new(new(networkStream), new(networkStream), networkStream);
    }

    private static void CreateTcpListener(AppSettings appSettings)
    {
        IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
        _TcpListener = new(ipAddress, appSettings.TransmissionControlProtocolConfiguration.Port);
        _TcpListener.Start();
        BeginAcceptTcpClient();
    }

    private static void NetworkStreamCanRead(TransmissionControlProtocolConfiguration transmissionControlProtocolConfiguration, NetworkStream networkStream)
    {
        List<byte> results = [];
        byte[] bytes = new byte[1024];
        string directory = Path.Combine(transmissionControlProtocolConfiguration.Destination, transmissionControlProtocolConfiguration.IPAddress);
        if (!Directory.Exists(directory))
            _ = Directory.CreateDirectory(directory);
        do
        {
            int count = networkStream.Read(bytes, 0, bytes.Length);
            if (count > 0)
                results.AddRange(bytes.Take(count));
        }
        while (networkStream.DataAvailable);
        if (results.Count > 0)
            File.WriteAllBytes(string.Concat(directory, $"-{DateTime.Now.Ticks}{directory[^1]}.raw"), results.ToArray());
    }

    internal static bool ReadWrite(AppSettings appSettings, ILogger<Worker> logger)
    {
        lock (_Lock)
        {
            if (!appSettings.TransmissionControlProtocolConfiguration.Server)
                ReadFiles(appSettings.TransmissionControlProtocolConfiguration);
            if (!appSettings.TransmissionControlProtocolConfiguration.Server && _Record is not null)
            {
                TimeSpan timeSpan = new(DateTime.Now.Ticks - _LastWrite);
                if (_LastWrite == 0 || timeSpan.TotalMinutes > 1)
                {
                    try
                    {
                        _Record.NetworkStream.WriteByte(Convert.ToByte('\0'));
                        _LastWrite = DateTime.Now.Ticks;
                    }
                    catch (Exception)
                    { }
                }
            }
            if (!appSettings.TransmissionControlProtocolConfiguration.Server && (_Record?.NetworkStream is null || !_Record.NetworkStream.Socket.Connected))
                CreateClient(appSettings, logger);
            else if (appSettings.TransmissionControlProtocolConfiguration.Server && _TcpListener is null)
                CreateTcpListener(appSettings);
            if (_Record?.NetworkStream is not null && _Record.NetworkStream.CanRead && _Record.NetworkStream.DataAvailable)
                NetworkStreamCanRead(appSettings.TransmissionControlProtocolConfiguration, _Record.NetworkStream);
            if (appSettings.TransmissionControlProtocolConfiguration.Server && _TcpListener is not null && _Record?.NetworkStream is not null && _Record.NetworkStream.CanWrite)
            {
                try
                {
                    _Record.BinaryWriter.Write("json");
                }
                catch (Exception)
                {
                    BeginAcceptTcpClient();
                }
            }
        }
        return true;
    }

}