using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Text;
using System.Threading.Channels;
using console_opcua_sgdn_tornio.Controllers;
using console_opcua_sgdn_tornio.Models;

namespace console_opcua_sgdn_tornio.Service
{
    public class QueuePolling : BackgroundService
    {
        private readonly string _connectionString;

        public QueuePolling(IConfiguration config, Channel<OpcUaQueue> queue)
        {
            _connectionString = config.GetConnectionString("PortalPFMSql");
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            Serilog.Log.Logger.Information("SQL Polling Service started.");

            while (!stoppingToken.IsCancellationRequested)
            {
                try
                {
                    await PollDatabaseAsync(stoppingToken);
                }
                catch (Exception ex)
                {
                    Serilog.Log.Logger.Error(ex, "Errore durante il polling SQL");
                }

                await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
            }

            Serilog.Log.Logger.Information("SQL Polling Service stopped.");
        }

        private async Task PollDatabaseAsync(CancellationToken cancellationToken)
        {
            using var connection = new SqlConnection(_connectionString);
            await connection.OpenAsync(cancellationToken);

            var command = new SqlCommand(
                """
                SELECT [ID]
                    ,[ProdId]
                    ,[JsonValues]
                    ,[IsSentToMachine]
                    ,[IsSentToAx]
                    ,[CreatedBy]
                    ,[CreatedDateTime]
                    ,[WrkCtrId]
                    ,[IsInError]
                    ,[ErrorString]
                    ,[WrkCtrRecId]
                FROM [db_PalFactoryMonitoring].[dbo].[OPC_UA_Queue]
                WHERE [IsSentToMachine] = 0
                """,
                connection);

            using var reader = await command.ExecuteReaderAsync(cancellationToken);

            while (await reader.ReadAsync(cancellationToken))
            {
                var id = reader.GetInt32(0);
                var prodId = reader.GetString(1);

                Serilog.Log.Logger.Information("Trovato job {Id} con stato {ProdId}", id, prodId);

                var record = new OpcUaQueue()
                {
                    ID = id,
                    ProdId = prodId,
                    JsonValues = reader.GetString(2),
                    IsSentToMachine = reader.GetBoolean(3),
                    IsSentToAx = reader.GetBoolean(4),
                    CreatedBy = reader.GetString(5),
                    CreatedDateTime = reader.GetDataTypeName(6),
                    WrkCtrId = reader.GetString(7),
                    IsInError = reader.GetBoolean(8),
                    ErrorString = reader.GetString(9),
                    WrkCtrRecId = reader.GetInt64(10)
                };

                await ProcessJobAsync(record, cancellationToken);
            }
        }

        private async Task ProcessJobAsync(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 IsSentToMachine = 1
                WHERE ID = @Id
                """,
                connection);

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

            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);
        }

    }
}
