using Edge.Core.Processor;using Edge.Core.IndustryStandardInterface.Pump;using Edge.Core.IndustryStandardInterface.Pump;
using Dfs.WayneChina.HengshanFPos.FPosDbManager;
using Dfs.WayneChina.SpsDbModels.Models;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Dfs.WayneChina.CardTrxManager.TrxScanner
{
    /// <summary>
    /// Scans the IC card trx within Hengshan MySQL Sps_db (table TrdInfo)
    /// </summary>
    public class TrxScanner
    {
        private FPosDbManager fPosDbManager;

        public event EventHandler<MatchingTrxFoundEventArgs> OnMatchingTrxFound;
        public event EventHandler<NoMatchFoundEventArgs> OnNoMatchFound;

        private static NLog.Logger scannerLogger = NLog.LogManager.LoadConfiguration("Nlog.config").GetLogger("TrxScanner");

        private readonly int retryLimit = 30;

        public TrxScanner(FPosDbManager fPosDbManager)
        {
            this.fPosDbManager = fPosDbManager;
        }

        public void StartScanAsync(int fdcPumpId, int epsSqNo, int fdcSeqNo, int releaseToken, FdcTransaction fdcTrx)
        {
            bool matchFound = false;
            int retries = retryLimit;
            //default set to Cash, which should be handled by indoor POS.
            var paymentMethod = "CASH";
            Task.Run(async () =>
            {
                using (var db = new SpsDbContext())
                {
                    TTrdinfo matchingRecord = null;
                    while (retries-- >= 0)
                    {
                        try
                        {
                            scannerLogger.Debug($"Starting to find a matching record with Fdc Pump Id: {fdcPumpId}, EpsSeqNo: {epsSqNo}");

                            //
                            //PaymodeId = 100, customer card payment
                            //PaymodeId = 103, operator card payment
                            //
                            matchingRecord = db.TTrdinfo
                            .OrderByDescending(t => t.TtctimeEnd)
                            .FirstOrDefault(t => t.PumpNo == (byte)(fdcPumpId)
                                && t.PaymodeId.HasValue && (t.PaymodeId.Value == 100 || t.PaymodeId.Value == 103)
                                && t.SeqNo.HasValue && t.SeqNo == epsSqNo
                                && t.Mon.Value != 0
                                && (t.TrdType == 0x00 || t.TrdType == 0x01) // 0x00 = Normal trx; 0x01 = Gray card trx.
                                && (DateTime.Now - t.Ttctime).TotalMinutes < TimeSpan.FromDays(1).TotalMinutes);

                            if (matchingRecord != null)
                            {
                                scannerLogger.Info("Found the matching record in MySql");
                                // only Customer IC Card paid trx treated as 'IC'
                                paymentMethod =
                                    (matchingRecord.CardType.HasValue && (matchingRecord.CardType == (byte)ICCardType.Customer))
                                        ? "IC"
                                        : "CASH";

                                if (matchingRecord.CardType.HasValue && (matchingRecord.CardType == (byte)ICCardType.Customer))
                                {
                                    fPosDbManager.SetCardType((ushort)matchingRecord.SeqNo, fdcSeqNo, (int)ICCardType.Customer);
                                    scannerLogger.Info($"match found, set card type to {ICCardType.Customer}");
                                }

                                scannerLogger.Debug($"      The matching trx is paid with MOP: {paymentMethod}");
                                matchFound = true;
                            }
                            else
                            {
                                scannerLogger.Info("No matching trx found in MySql at this round");
                            }
                        }
                        catch (Exception e)
                        {
                            scannerLogger.Info("Exception in finding the matching transaction: " + e);
                        }

                        if (matchFound || retries == 0)
                            break;

                        int round = retryLimit - retries;

                        if (round <= 5)
                        {
                            scannerLogger.Info($"Scan count: {round}");
                        }
                        else if (round > 5 && round <= 10)
                        {
                            scannerLogger.Info($"# Scan count: {round}");
                        }
                        else if (round > 10 && round <= 20)
                        {
                            scannerLogger.Info($"## Scan count: {round}");
                        }
                        else
                        {
                            scannerLogger.Info($"### Scan count: {round}");
                        }

                        await Task.Delay(1000);
                    }

                    if (matchFound)
                    {
                        scannerLogger.Info($"CardNo: {matchingRecord.CardNo}, RealMon: {matchingRecord.RealMon}");

                        fPosDbManager.SetActualPayAmount((ushort)epsSqNo, fdcSeqNo, (decimal)matchingRecord.RealMon / 100);

                        scannerLogger.Info($"Set ActualPayAmount { (decimal)matchingRecord.RealMon / 100} to FPOS trx SqNo: {epsSqNo}");

                        OnMatchingTrxFound?.Invoke(this, new MatchingTrxFoundEventArgs
                        {
                            MOP = paymentMethod,
                            QRCode = matchingRecord.CardNo,
                            FdcSqNo = fdcSeqNo,
                            ReleaseToken = releaseToken,
                            TrdInfo = matchingRecord,
                            FdcTrx = fdcTrx
                        });
                    }
                    else
                    {
                        scannerLogger.Info("Could not find a match, giving up...");
                        OnNoMatchFound?.Invoke(this, new NoMatchFoundEventArgs
                        {
                            FdcSqNo = fdcSeqNo,
                            ReleaseToken = releaseToken,
                            FdcTrx = fdcTrx
                        });
                    }
                }
            });
        }
    }
}