using Dapper;
using EVCB_OCPP.Domain;
using EVCB_OCPP.Domain.Models.Database;
using EVCB_OCPP.Packet.Features;
using EVCB_OCPP.Packet.Messages.Core;
using EVCB_OCPP.WSServer.Dto;
using EVCB_OCPP.WSServer.Message;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using OCPPServer.Protocol;
using Quartz;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;

namespace EVCB_OCPP.WSServer.Jobs;

[DisallowConcurrentExecution]
public class ServerSetFeeJob : IJob
{
    private readonly ProtalServer protalServer;
    private readonly IDbContextFactory<MainDBContext> maindbContextFactory;
    private readonly ILogger<ServerSetFeeJob> logger;
    private readonly string webConnectionString;

    public ServerSetFeeJob(
        ProtalServer protalServer,
        IConfiguration configuration,
        IDbContextFactory<MainDBContext> maindbContextFactory,
        ILogger<ServerSetFeeJob> logger) 
    {
        this.protalServer = protalServer;
        this.maindbContextFactory = maindbContextFactory;
        this.logger = logger;
        this.webConnectionString = configuration.GetConnectionString("WebDBContext");
    }

    public async Task Execute(IJobExecutionContext context)
    {
        //logger.LogDebug("{0} Started", nameof(ServerSetFeeJob));
        BasicMessageHandler msgAnalyser = new BasicMessageHandler();
        Dictionary<string, ClientData> _copyClientDic = protalServer.ClientDic;
        using var db = maindbContextFactory.CreateDbContext();
        foreach (var item in _copyClientDic)
        {
            try
            {
                ClientData session = item.Value;
                if (!session.IsCheckIn)
                {
                    continue;
                }

                string displayPriceText = await SetDefaultFee(session);
                if (string.IsNullOrEmpty(displayPriceText) || displayPriceText == session.DisplayPrice)
                {
                    continue;
                }

                protalServer.UpdateClientDisplayPrice(item.Key, displayPriceText);

                var _CheckFeeDt = DateTime.UtcNow;
                    db.ServerMessage.Add(new ServerMessage()
                    {
                        ChargeBoxId = session.ChargeBoxId,
                        CreatedBy = "Server",
                        CreatedOn = _CheckFeeDt,
                        OutAction = Actions.ChangeConfiguration.ToString(),
                        OutRequest = JsonConvert.SerializeObject(
                                new ChangeConfigurationRequest()
                                {
                                    key = "DefaultPrice",
                                    value = displayPriceText
                                },
                                new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
                        SerialNo = Guid.NewGuid().ToString(),
                        InMessage = string.Empty

                    });

                    if (session.CustomerId == new Guid("10C7F5BD-C89A-4E2A-8611-B617E0B41A73"))
                    {
                        db.ServerMessage.Add(new ServerMessage()
                        {
                            ChargeBoxId = session.ChargeBoxId,
                            CreatedBy = "Server",
                            CreatedOn = _CheckFeeDt,
                            OutAction = Actions.ChangeConfiguration.ToString(),
                            OutRequest = JsonConvert.SerializeObject(
                               new ChangeConfigurationRequest()
                               {
                                   key = "ConnectionTimeOut",
                                   value = "120"
                               },
                               new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
                            SerialNo = Guid.NewGuid().ToString(),
                            InMessage = string.Empty

                        });
                        db.ServerMessage.Add(new ServerMessage()
                        {
                            ChargeBoxId = session.ChargeBoxId,
                            CreatedBy = "Server",
                            CreatedOn = _CheckFeeDt,
                            OutAction = Actions.ChangeConfiguration.ToString(),
                            OutRequest = JsonConvert.SerializeObject(
                               new ChangeConfigurationRequest()
                               {
                                   key = "MeterValueSampleInterval",
                                   value = "3"
                               },
                               new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
                            SerialNo = Guid.NewGuid().ToString(),
                            InMessage = string.Empty

                        });
                    }

                    db.SaveChanges();
                    db.ChangeTracker.Clear();
            }
            catch (Exception ex)
            {
                logger.LogError("ServerSetFeeTrigger ChargeBoxId:{0}  Ex:{1}", item.Key, ex.ToString());
            }
        }
    }

    async private Task<string> SetDefaultFee(ClientData client)
    {
        string displayPriceText = string.Empty;
        string charingPriceText = string.Empty;

        if (string.IsNullOrEmpty(client.ChargeBoxId)) return displayPriceText;

        using (SqlConnection conn = new SqlConnection(webConnectionString))
        {
            var parameters = new DynamicParameters();
            parameters.Add("@MachineId", client.MachineId, DbType.String, ParameterDirection.Input, 36);
            string displayPricestrSql = "";
            string strSql = "";

            if (client.IsAC)
            {
                displayPricestrSql = """
                    SELECT [AC_BillingMethod] as BillingMethod,[AC_FeeName] as FeeName,[AC_Fee] as ChargingFeebyHour ,[AC_ParkingFee] as ParkingFee, [Currency] 
                    FROM[StationMachine] left join[dbo].[Station]
                    on[StationMachine].StationId = Station.[Id] 
                    where StationMachine.MachineId=@MachineId and Station.IsBilling=1;
                    """;

                strSql = """
                    SELECT CAST( [StartTime] as varchar(5)) StartTime,CAST( [EndTime] as varchar(5)) EndTime,[Fee] 
                    FROM[StationMachine] left join [dbo].[StationFee]
                    on[StationMachine].StationId = StationFee.StationId  
                    where StationMachine.MachineId =@MachineId and StationFee.IsAC=1; 
                    """;
            }
            else
            {
                displayPricestrSql = """
                    SELECT [DC_BillingMethod] as BillingMethod,[DC_FeeName] as FeeName,[DC_Fee] as ChargingFeebyHour ,[DC_ParkingFee] as ParkingFee, [Currency] 
                    FROM[StationMachine] left join[dbo].[Station] 
                    on[StationMachine].StationId = Station.[Id]
                    where StationMachine.MachineId=@MachineId and Station.IsBilling=1; 
                    """;

                strSql = """
                    SELECT CAST( [StartTime] as varchar(5)) StartTime,CAST( [EndTime] as varchar(5)) EndTime,[Fee]
                    FROM[StationMachine] left join [dbo].[StationFee]
                    on[StationMachine].StationId = StationFee.StationId
                    where StationMachine.MachineId =@MachineId and StationFee.IsAC=0;
                    """;

            }
            var result = await conn.QueryAsync<StationFee>(displayPricestrSql, parameters);
            if (result.Count() == 0)
            {
                return string.Empty;
            }
            var stationPrice = result.First();

            if (stationPrice.BillingMethod == 1)
            {
                var chargingPriceResult = await conn.QueryAsync<ChargingPrice>(strSql, parameters);
                client.ChargingPrices = chargingPriceResult.ToList();
                if (string.IsNullOrEmpty(client.ChargingPrices[0].StartTime))
                {
                    client.ChargingPrices = new List<ChargingPrice>();
                }
            }

            displayPriceText = stationPrice.FeeName;
            client.BillingMethod = stationPrice.BillingMethod;
            client.Currency = stationPrice.Currency;
            client.ChargingFeebyHour = stationPrice.ChargingFeebyHour;
            client.ParkingFee = stationPrice.ParkingFee;
            client.IsBilling = true;
        }

        return displayPriceText;
    }
}
