using EVCB_OCPP.Domain;

using EVCB_OCPP.Packet.Features;
using EVCB_OCPP.Packet.Messages;
using EVCB_OCPP.Packet.Messages.FirmwareManagement;
using Newtonsoft.Json;

using System;
using System.Linq;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using EVCB_OCPP.WSServer.Service.WsService;
using EVCB_OCPP.Domain.Models.MainDb;

namespace EVCB_OCPP.WSServer.Message
{
    internal partial class ProfileHandler
    {
        internal async Task<MessageResult> ExecuteFirmwareManagementRequest(Actions action, WsClientData session, IRequest request)
        {
            MessageResult result = new MessageResult() { Success = false };
            try
            {
                switch (action)
                {

                    case Actions.FirmwareStatusNotification:
                        {
                            FirmwareStatusNotificationRequest _request = request as FirmwareStatusNotificationRequest;

                            if (_request.status == Packet.Messages.SubTypes.FirmwareStatus.Idle)
                            {
                                string requestId = Guid.NewGuid().ToString();
                                using (var db = await maindbContextFactory.CreateDbContextAsync())
                                {
                                    var machine = await db.Machine.Where(x => x.FwAssignedVersion.HasValue == true && x.FwAssignedVersion.HasValue
                                       && x.FwAssignedVersion != x.FwVersionReport && x.ChargeBoxId == session.ChargeBoxId)
                                        .Select(x => new { x.Id, x.FwAssignedVersion }).AsNoTracking().FirstOrDefaultAsync();

                                    if (machine != null)
                                    {
                                        var mv = db.MachineVersionFile.Include(c => c.UploadFile)
                                         .Where(c => c.Id == machine.FwAssignedVersion.Value).First();

                                        string downloadUrl = mv.UploadFile.FileUrl;

                                        var _updateFWrequest = new UpdateFirmwareRequest()
                                        {
                                            location = new Uri(downloadUrl),
                                            retries = 3,
                                            retrieveDate = DateTime.UtcNow,
                                            retryInterval = 10
                                        };

                                        await db.MachineOperateRecord.AddAsync(new MachineOperateRecord()
                                        {
                                            CreatedOn = DateTime.UtcNow,
                                            ChargeBoxId = session.ChargeBoxId,
                                            SerialNo = requestId,
                                            RequestContent = JsonConvert.SerializeObject(_updateFWrequest, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
											EvseStatus = 0,
											EvseValue = "Fw Version:" + machine.FwAssignedVersion,
                                            Status = 0,
                                            RequestType = 0,
                                            Action = _updateFWrequest.Action.ToString()

                                        });

                                        await db.SaveChangesAsync();

                                        await mainDbService.AddServerMessage(
                                            ChargeBoxId: session.ChargeBoxId,
                                            OutAction: _updateFWrequest.Action.ToString(),
                                            OutRequest: _updateFWrequest,
                                            SerialNo: requestId);

                                        var clearMachine = await db.Machine.Where(x => x.Id == machine.Id).FirstOrDefaultAsync();
                                        clearMachine.FwAssignedVersion = null;
                                        await db.SaveChangesAsync();
                                    }

                                }
                            }
                            else
                            {
                                using (var db = await maindbContextFactory.CreateDbContextAsync())
                                {
                                    var item = await db.MachineOperateRecord.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.Action == "UpdateFirmware" && x.RequestType == 0)
                                        .OrderByDescending(x => x.CreatedOn).FirstOrDefaultAsync();
                                    if (item != null)
                                    {
                                        item.EvseStatus = (int)_request.status;
                                        item.FinishedOn = DateTime.UtcNow;
                                    }

                                    await db.SaveChangesAsync();
                                }
                            }

                            var confirm = new FirmwareStatusNotificationConfirmation() { };

                            result.Message = confirm;
                            result.Success = true;
                        }
                        break;
                    case Actions.DiagnosticsStatusNotification:
                        {
                            DiagnosticsStatusNotificationRequest _request = request as DiagnosticsStatusNotificationRequest;

                            if (_request.status != Packet.Messages.SubTypes.DiagnosticsStatus.Idle)
                            {
                                using (var db = await maindbContextFactory.CreateDbContextAsync())
                                {
                                    var item = db.MachineOperateRecord.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.Action == "GetDiagnostics" && x.RequestType == 1)
                                        .OrderByDescending(x => x.CreatedOn).FirstOrDefault();
                                    if (item != null)
                                    {
                                        item.EvseStatus = (int)_request.status;
                                        item.FinishedOn = DateTime.UtcNow;
                                    }

                                    await db.SaveChangesAsync();
                                }

                            }

                            var confirm = new DiagnosticsStatusNotificationConfirmation() { };

                            result.Message = confirm;
                            result.Success = true;

                        }
                        break;

                    default:
                        {
                            logger.LogWarning(string.Format("Not Implement {0} Logic", request.GetType().ToString().Replace("OCPPPackage.Messages.FirmwareManagement.", "")));
                        }
                        break;
                }
            }
            catch (Exception ex)
            {
                logger.LogCritical("chargeBoxId:{0} {1}", session.ChargeBoxId, action);
                logger.LogCritical("Data {0}", request.ToString());
                logger.LogCritical("Error {0}", ex.ToString());
                result.Exception = ex;
            }
            return result;
        }

        internal async Task<MessageResult> ExecuteFirmwareManagementConfirm(Actions action, WsClientData session, IConfirmation confirm, string requestId)
        {
            MessageResult result = new MessageResult() { Success = true };

            switch (action)
            {
                case Actions.UpdateFirmware:
                case Actions.GetDiagnostics:
                    {
                        string evse_rep = string.Empty;
                        if (confirm is GetDiagnosticsConfirmation)
                        {
                            var confirmation = confirm as GetDiagnosticsConfirmation;
                            evse_rep = confirmation.fileName;
                        }
                        using (var db = await maindbContextFactory.CreateDbContextAsync())
                        {
                            var operation = await db.MachineOperateRecord
                                .Where(x => x.SerialNo == requestId && x.ChargeBoxId == session.ChargeBoxId && x.Status == 0)
                                .FirstOrDefaultAsync();
                            if (operation != null)
                            {
                                operation.FinishedOn = DateTime.UtcNow;
                                operation.Status = 1;//電樁有回覆
                                operation.EvseValue = string.IsNullOrEmpty(evse_rep) ? operation.EvseValue : evse_rep;
                                await db.SaveChangesAsync();
                            }

                        }
                    }
                    break;
                default:
                    {
                        logger.LogWarning(string.Format("Not Implement {0} Logic", confirm.GetType().ToString().Replace("OCPPPackage.Messages.FirmwareManagement.", "")));
                    }
                    break;
            }
            return result;
        }


        internal async Task<MessageResult> ReceivedFirmwareManagementError(Actions action, string errorMsg, WsClientData session, string requestId)
        {
            MessageResult result = new MessageResult() { Success = true };

            switch (action)
            {
                case Actions.FirmwareStatusNotification:
                case Actions.UpdateFirmware:
                case Actions.GetDiagnostics:
                case Actions.DiagnosticsStatusNotification:
                    {
                        using (var db = await maindbContextFactory.CreateDbContextAsync())
                        {
                            var operation = await db.MachineOperateRecord
                                .Where(x => x.SerialNo == requestId && x.ChargeBoxId == session.ChargeBoxId && x.Status == 0)
                                .FirstOrDefaultAsync();
                            if (operation != null)
                            {
                                operation.FinishedOn = DateTime.UtcNow;
                                operation.Status = 1;//電樁有回覆
                                operation.EvseStatus = (int)255;//錯誤
                                operation.EvseValue = errorMsg;
                                await db.SaveChangesAsync();
                            }

                        }
                    }
                    break;

                default:
                    {
                        logger.LogWarning(string.Format("Not Implement {0} Logic", action));
                    }
                    break;
            }
            return result;

        }
    }
}