using EVCB_OCPP.Domain;
using EVCB_OCPP.Domain.Models.Database;
using EVCB_OCPP.Packet.Features;
using EVCB_OCPP.Packet.Messages;
using EVCB_OCPP.Packet.Messages.FirmwareManagement;
using Newtonsoft.Json;
using OCPPServer.Protocol;
using System;
using System.Linq;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;

namespace EVCB_OCPP.WSServer.Message
{
    internal partial class ProfileHandler
    {
        internal async Task<MessageResult> ExecuteFirmwareManagementRequest(Actions action, ClientData 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 = maindbContextFactory.CreateDbContext())
                                {
                                    var machine = await db.Machine.Where(x => x.FW_AssignedVersion.HasValue == true && x.FW_AssignedVersion.HasValue
                                       && x.FW_AssignedVersion != x.FW_VersionReport && x.ChargeBoxId == session.ChargeBoxId)
                                        .Select(x => new { x.Id, x.FW_AssignedVersion }).AsNoTracking().FirstOrDefaultAsync();

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

                                        string downloadUrl = mv.UploadFile.FileUrl;

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

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

                                        });

                                        db.ServerMessage.Add(new ServerMessage()
                                        {
                                            ChargeBoxId = session.ChargeBoxId,
                                            CreatedBy = "Server",
                                            CreatedOn = DateTime.UtcNow,
                                            OutAction = _updateFWrequest.Action.ToString(),
                                            OutRequest = JsonConvert.SerializeObject(_updateFWrequest, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }),
                                            SerialNo = requestId,
                                            InMessage = string.Empty

                                        });

                                        db.SaveChanges();

                                    }

                                }
                            }
                            else
                            {
                                using (var db = maindbContextFactory.CreateDbContext())
                                {
                                    var item = await db.MachineOperateRecord.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.RequestType == 0)
                                        .OrderByDescending(x => x.CreatedOn).FirstOrDefaultAsync();
                                    if (item != null)
                                    {
                                        item.EVSE_Status = (int)_request.status;
                                        item.FinishedOn = DateTime.UtcNow;
                                        if (string.IsNullOrEmpty(item.EVSE_Value))
                                        {
                                            Console.WriteLine("怎麼悾悾的");
                                        }

                                        if (!string.IsNullOrEmpty(item.EVSE_Value) && _request.status == Packet.Messages.SubTypes.FirmwareStatus.Installed)
                                        {
                                            int version = 0;
                                            int.TryParse(item.EVSE_Value.Split(':').Last(), out version);
                                            var machine = await db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId).FirstOrDefaultAsync();
                                            machine.FW_VersionReport = version;
                                        }
                                    }



                                    db.SaveChanges();
                                }
                            }

                            var confirm = new FirmwareStatusNotificationConfirmation() { };

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

                            var confirm = new DiagnosticsStatusNotificationConfirmation() { };

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

                        }
                        break;

                    default:
                        {
                            Console.WriteLine(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, ClientData 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 = maindbContextFactory.CreateDbContext())
                        {
                            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.EVSE_Status = (int)1;//OK
                                operation.EVSE_Value = string.IsNullOrEmpty(evse_rep) ? operation.EVSE_Value : evse_rep;
                                db.SaveChanges();
                            }

                        }
                    }
                    break;
                default:
                    {
                        Console.WriteLine(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, ClientData 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 = maindbContextFactory.CreateDbContext())
                        {
                            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.EVSE_Status = (int)255;//錯誤
                                operation.EVSE_Value = errorMsg;
                                db.SaveChanges();
                            }

                        }
                    }
                    break;

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

        }
    }
}
