using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Orleans;
using Orleans.Concurrency;
using Orleans.Runtime;
using UnitTests.GrainInterfaces;


namespace UnitTests.Grains
{
    [StatelessWorker(MaxLocalWorkers)]
    public class StatelessWorkerGrain : Grain, IStatelessWorkerGrain
    {
        public const int MaxLocalWorkers = 1;

        private Guid activationGuid;
        private readonly List<Tuple<DateTime, DateTime>> calls = new List<Tuple<DateTime, DateTime>>();
        private Logger logger;
        private static HashSet<Guid> allActivationIds = new HashSet<Guid>();

        public override Task OnActivateAsync()
        {
            activationGuid = Guid.NewGuid();
            logger = GetLogger(String.Format("{0}", activationGuid));
            logger.Info("Activate.");
            return TaskDone.Done;
        }

        public Task LongCall()
        {
            int count = 0;
            lock (allActivationIds)
            {
                if (!allActivationIds.Contains(activationGuid))
                {
                    allActivationIds.Add(activationGuid);
                }
                count = allActivationIds.Count;
            }
            DateTime start = DateTime.UtcNow;
            TaskCompletionSource<bool> resolver = new TaskCompletionSource<bool>();
            RegisterTimer(TimerCallback, resolver, TimeSpan.FromSeconds(2), TimeSpan.FromMilliseconds(-1));
            return resolver.Task.ContinueWith(
                (_) =>
                {
                    DateTime stop = DateTime.UtcNow;
                    calls.Add(new Tuple<DateTime, DateTime>(start, stop));
                    logger.Info((stop - start).TotalMilliseconds.ToString());
                    logger.Info($"Start {LogFormatter.PrintDate(start)}, stop {LogFormatter.PrintDate(stop)}, duration {stop - start}. #act {count}");
                });
        }

        private static Task TimerCallback(object state)
        {
            ((TaskCompletionSource<bool>)state).SetResult(true);
            return TaskDone.Done;
        }


        public Task<Tuple<Guid, string, List<Tuple<DateTime, DateTime>>>> GetCallStats()
        {
            Thread.Sleep(200);
            string silo = RuntimeIdentity;
            List<Guid> ids;
            lock (allActivationIds)
            {
                ids = allActivationIds.ToList();
            }
            logger.Info($"# allActivationIds {ids.Count} for silo {silo}: {Utils.EnumerableToString(ids)}");
            return Task.FromResult(Tuple.Create(activationGuid, silo, calls));
        }
    }
}
