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.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.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
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;
            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;
                    using (var db = await maindbContextFactory.CreateDbContextAsync())
                    {
                        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

                            });
                        }

                        await db.SaveChangesAsync();

                    }

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