using console_opcua_sgdn_tornio.Controllers;
using console_opcua_sgdn_tornio.Models;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using System.Data.SqlClient;
using System.Net.NetworkInformation;
using System.Threading;
using System.Threading.Channels;
using static Org.BouncyCastle.Math.EC.ECCurve;

namespace console_opcua_sgdn_tornio.Service
{

    // ?? MachinePolling da portare a ParpasPolling o gestirlo sotto?
    public class MachinePolling : BackgroundService
    {
        private OpcUaSettings _opcUaSettings;
        private string _connectionString;
        public MachinePolling(IConfiguration configuration)
        {
            _opcUaSettings = configuration.GetSection("OpcUaParpasSettings").Get<OpcUaSettings>();
            _connectionString = configuration.GetConnectionString("PortalPFMSql");

        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            await foreach (var job in JobChannel.Channel.Reader.ReadAllAsync(stoppingToken))
            {
                Serilog.Log.Logger.Information("Inizio processing Job {Id}", job.ID);

                if (await PingWithRetryAsync(_opcUaSettings.DnsName, cancellationToken: stoppingToken))
                {
                    await ProcessJobAsync(job, stoppingToken);
                }
                else
                {
                    job.ErrorString = "Impossibile contattare la macchina dopo più tentativi.";
                    await ClosingRecordWithErrorAsync(job, stoppingToken);
                }

                Serilog.Log.Logger.Information("Fine processing Job {Id}", job.ID);
            }
        }

        #region MainProcess
        
        private async Task ProcessJobAsync(OpcUaQueue job, CancellationToken ct)
        {
            // Connessione a OPCUA e logiche varie
            OpcUaConnection ouc = new OpcUaConnection(_opcUaSettings, ct);
            ouc.ConnectAsync();




            // qui DB update, chiamate API, ecc.
        }
        
        #endregion

        #region Utility

        private async Task<bool> PingWithRetryAsync(string host, int maxAttempts = 5, CancellationToken cancellationToken = default)
        {
            using var ping = new Ping();

            for (int attempt = 1; attempt <= maxAttempts; attempt++)
            {
                cancellationToken.ThrowIfCancellationRequested();

                try
                {
                    var reply = await ping.SendPingAsync(host, 3000);

                    if (reply.Status == IPStatus.Success)
                        return true;
                }
                catch
                {
                    Serilog.Log.Logger.Warning($"Non è stato possibile contattare la macchina tentativo {attempt} di {maxAttempts}");

                }

                if (attempt < maxAttempts)
                    await Task.Delay(TimeSpan.FromSeconds(60), cancellationToken);
            }


            Serilog.Log.Logger.Error($"Non è stato possibile contattare la macchina");
            return false;
        }

        #endregion

        #region SQL
        
        private async Task ClosingRecordWithErrorAsync(OpcUaQueue job, CancellationToken cancellationToken)
        {
            using var connection = new SqlConnection(_connectionString);
            await connection.OpenAsync(cancellationToken);

            var command = new SqlCommand(
                """
                UPDATE [db_PalFactoryMonitoring].[dbo].[OPC_UA_Queue]
                SET IsInError = 1, ErrorString = @Error
                WHERE ID = @Id
                """,
                connection);

            command.Parameters.AddWithValue("@Id", job.ID);
            command.Parameters.AddWithValue("@Error", job.ErrorString);

            await command.ExecuteNonQueryAsync(cancellationToken);

            await JobChannel.Channel.Writer.WriteAsync(job, cancellationToken);

            Serilog.Log.Logger.Information("Job {Id} pronto per essere inviato in macchiana", job.ID);
        }
        #endregion
    }
}
