using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Threading;

namespace BulkPrinting
{
    public class LogUploader : ThreadHelper
    {
        private const int _uploadPageSize = 5000;
        private const int _retryInterval = 30000;

        private DBHelper _db;
        private bool _uploadTriggered;

        public LogUploader(DBHelper db)
        {
            _db = db;
        }

        protected override void Run()
        {
            var isCancelled = false;
            while (!isCancelled)
            {
                var uploadFailed = false;
                int lastSyncedLogId = Utility.GetLastSyncedLogID();

                var result = _db.ExecuteScalar("SELECT MAX(Id) FROM Logs")?.ToString() ?? "0";
                if (string.IsNullOrWhiteSpace(result))
                {
                    result = "0";
                }
                int lastRecordedLogId = int.Parse(result.ToString());

                if (lastRecordedLogId > lastSyncedLogId)
                {
                    List<RemoteVendorEvent> eventList = new List<RemoteVendorEvent>();
                    int counter = 0;
                    using (var Command = _db.CreateCommand(
                        "Select Id,UserId,VoucherId,EventDate,EventType,Retry From Logs WHERE Id > @id",
                        new SQLiteParameter("@id", lastSyncedLogId)))
                    {
                        using (SQLiteDataReader read = Command.ExecuteReader())
                        {
                            while (read.Read())
                            {
                                counter += 1;
                                var nextEvent = new RemoteVendorEvent();
                                nextEvent.Id = read.GetInt32(0);
                                nextEvent.UserId = read.GetInt32(1);
                                if (read.IsDBNull(2) == true)
                                {
                                    nextEvent.VoucherId = null;
                                }
                                else
                                {
                                    nextEvent.VoucherId = read.GetInt32(2);
                                }
                                nextEvent.EventDate = read.GetDateTime(3);
                                nextEvent.EventType = (VendorEvent.VendorEventType)Enum.Parse(typeof(VendorEvent.VendorEventType), read.GetValue(4).ToString());
                                nextEvent.VendorId = Globals.SessionData.Credentials.Payload.Vendor.id;
                                nextEvent.Retry = read.GetBoolean(5);
                                eventList.Add(nextEvent);

                                if (counter == _uploadPageSize)
                                {
                                    var response = new RemoteVendorEventResponse();
                                    if (Utility.RESTRequest(eventList, ref response, "/api/vendorevents/"))
                                    {
                                        counter = 0;
                                        eventList.Clear();
                                    }
                                    else
                                    {
                                        uploadFailed = true;
                                        break;
                                    }
                                }
                            }
                            if ((counter > 0) && ! uploadFailed)
                            {
                                var response = new RemoteVendorEventResponse();
                                if (!Utility.RESTRequest(eventList, ref response, "/api/vendorevents/"))
                                {
                                    uploadFailed = true;
                                }
                            }
                        }
                    }
                }

                lock (_lock)
                {
                    while (!_cancelled && !_uploadTriggered)
                    {
                        Monitor.Wait(_lock, uploadFailed ? _retryInterval : Timeout.Infinite);
                        if (uploadFailed)
                        {
                            break;
                        }
                    }
                    _uploadTriggered = false;
                    isCancelled = _cancelled;
                }
            }
        }

        public void TriggerUpload()
        {
            lock (_lock)
            {
                _uploadTriggered = true;
                Monitor.Pulse(_lock);
            }
        }
    }
}
