using System;
using System.Threading;

namespace BulkPrinting
{
    public class DownloadedLogSummariser : ThreadHelper
    {
        private const int _retryInterval = 30000;

        private DBHelper _db;
        private Action _refreshAction;

        public DownloadedLogSummariser(DBHelper db, Action refreshAction)
        {
            _db = db;
            _refreshAction = refreshAction;
        }

        protected override void Run()
        {
            bool isCancelled = false;
            while (!isCancelled)
            {
                bool doRefresh = false;

                while (!isCancelled)
                {
                    lock (_db.WriteLock)
                    {
                        using (var trans = _db.BeginTransaction())
                        {
                            using (var selectCommand = _db.CreateCommand(
                                "SELECT l.*, v.BatchId FROM Logs l " +
                                    "LEFT JOIN Voucher v ON l.VoucherId=v.Id " +
                                "WHERE Summarised=0 " +
                                "LIMIT 1000",
                                trans))
                            using (var updateLogsCommand = _db.CreateCommand(
                                "UPDATE Logs SET Summarised=1 WHERE Id=@Id"))
                            using (var updateVoucherCommand = Utility.CreateVoucherEventCountUpdateCommand(_db, trans))
                            using (var updateBatchCommand = Utility.CreateBatchEventCountUpdateCommand(_db, trans))
                            {
                                updateLogsCommand.Parameters.AddWithValue("@Id", null);

                                using (var reader = selectCommand.ExecuteReader())
                                {
                                    var rowCount = 0;
                                    while (reader.Read())
                                    {
                                        rowCount++;
                                        doRefresh = true;

                                        int printCountDelta, reprintCountDelta, exportCountDelta, reExportCountDelta;
                                        if ((reader["VoucherId"] != null) &&
                                            Utility.CalculateEventCountDeltas(
                                            (VendorEvent.VendorEventType)int.Parse((string)reader["EventType"]),
                                            (bool)reader["Retry"],
                                            out printCountDelta,
                                            out reprintCountDelta,
                                            out exportCountDelta,
                                            out reExportCountDelta))
                                        {
                                            Utility.ExecuteEventCountUpdateQuery(updateVoucherCommand, (int)reader["VoucherId"],
                                                printCountDelta, reprintCountDelta, exportCountDelta, reExportCountDelta);

                                            if (reader["BatchId"] != null)
                                            {
                                                Utility.ExecuteEventCountUpdateQuery(updateBatchCommand, (int)reader["BatchId"],
                                                    printCountDelta, reprintCountDelta, exportCountDelta, reExportCountDelta);
                                            }
                                        }

                                        var logId = (long)reader["Id"];

                                        updateLogsCommand.Parameters["@Id"].Value = (int)logId;
                                        updateLogsCommand.ExecuteNonQuery();
                                    }

                                    if (rowCount == 0)
                                    {
                                        break;
                                    }
                                }
                            }

                            trans.Commit();
                        }
                    }

                    lock (_lock)
                    {
                        isCancelled = _cancelled;
                    }
                }

                if (! isCancelled && doRefresh)
                {
                    doRefresh = false;
                    _refreshAction();
                }

                // We sleep and try again on the offchance that we got triggered too early.
                lock (_lock)
                {
                    if (!_cancelled)
                    {
                        Monitor.Wait(_lock, _retryInterval);
                    }
                    isCancelled = _cancelled;
                }
            }
        }
    }
}
