using System;
using System.Collections.Generic;

namespace FasdDesktopUi.Basics.Services.Models
{
    internal static class TicketOverviewCountProcessor
    {
        internal static ScopeCountProcessingResult Calculate(
            IReadOnlyDictionary<string, TileCounts> currentCounts,
            IEnumerable<string> overviewKeys,
            TileScope scope,
            IDictionary<string, int> incomingCounts,
            bool hasInitializedScope)
        {
            if (overviewKeys == null)
                throw new ArgumentNullException(nameof(overviewKeys));

            var updatedCounts = new Dictionary<string, TileCounts>(StringComparer.OrdinalIgnoreCase);
            if (currentCounts != null)
            {
                foreach (var kvp in currentCounts)
                {
                    updatedCounts[kvp.Key] = kvp.Value;
                }
            }

            var changes = new List<TileCountChange>();
            foreach (var key in overviewKeys)
            {
                var previous = currentCounts != null && currentCounts.TryGetValue(key, out var counts)
                    ? counts
                    : TileCounts.Empty;
                var incoming = incomingCounts != null && incomingCounts.TryGetValue(key, out var value)
                    ? value
                    : 0;

                TileCounts updated;
                int oldValue;

                if (scope == TileScope.Role)
                {
                    updated = new TileCounts(previous.Personal, incoming);
                    oldValue = previous.Role;
                }
                else
                {
                    updated = new TileCounts(incoming, previous.Role);
                    oldValue = previous.Personal;
                }

                updatedCounts[key] = updated;

                if (hasInitializedScope && oldValue != incoming)
                    changes.Add(new TileCountChange(key, scope, oldValue, incoming));
            }

            return new ScopeCountProcessingResult(updatedCounts, changes, !hasInitializedScope);
        }
    }

    internal sealed class ScopeCountProcessingResult
    {
        internal ScopeCountProcessingResult(
            IReadOnlyDictionary<string, TileCounts> updatedCounts,
            IReadOnlyList<TileCountChange> changes,
            bool isInitialization)
        {
            UpdatedCounts = updatedCounts ?? throw new ArgumentNullException(nameof(updatedCounts));
            Changes = changes ?? Array.Empty<TileCountChange>();
            IsInitialization = isInitialization;
        }

        internal IReadOnlyDictionary<string, TileCounts> UpdatedCounts { get; }

        internal IReadOnlyList<TileCountChange> Changes { get; }

        internal bool IsInitialization { get; }
    }
}
