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.Helper;
using EVCB_OCPP.WSServer.Message;
using EVCB_OCPP.WSServer.Service;
using EVCB_OCPP.WSServer.Service.WsService;
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 SqlConnectionFactory<WebDBConetext> webDbConnectionFactory;
    private readonly ServerMessageService messageService;
    private readonly IMainDbService mainDbService;
    private readonly ILogger<ServerSetFeeJob> logger;
    //private readonly string webConnectionString;

    public ServerSetFeeJob(
        ProtalServer protalServer,
        //IConfiguration configuration,
        SqlConnectionFactory<WebDBConetext> sqlConnectionFactory,
        ServerMessageService messageService,
        IMainDbService mainDbService,
        ILogger<ServerSetFeeJob> logger)
    {
        this.protalServer = protalServer;
        this.webDbConnectionFactory = sqlConnectionFactory;
        this.messageService = messageService;
        this.mainDbService = mainDbService;
        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, WsClientData> _copyClientDic = protalServer.GetClientDic();
        //using var db = maindbContextFactory.CreateDbContextAsync();
        foreach (var item in _copyClientDic)
        {
            try
            {
                WsClientData 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);

                await messageService.SendChangeConfigurationRequest(
                    session.ChargeBoxId, key: "DefaultPrice", value: displayPriceText);

                if (session.CustomerId == new Guid("10C7F5BD-C89A-4E2A-8611-B617E0B41A73"))
                {
                    await messageService.SendChangeConfigurationRequest(
                        session.ChargeBoxId, key: "ConnectionTimeOut", value: "120");

                    await messageService.SendChangeConfigurationRequest(
                        session.ChargeBoxId, key: "MeterValueSampleInterval", value: "3");
                }
            }
            catch (Exception ex)
            {
                logger.LogError("ServerSetFeeTrigger ChargeBoxId:{0}  Ex:{1}", item.Key, ex.ToString());
            }
        }
    }

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

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

        try
        {
            using (SqlConnection conn = await webDbConnectionFactory.CreateAsync())
            {
                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;
            }
        }
        catch (Exception ex)
        {
            logger.LogError("SetDefaultFee", ex.ToString());
        }

        return displayPriceText;
    }
}