using System;
using System.Collections.Generic;

namespace DataImport
{
    public class ContentFile
    {
        public List<Activity> activities;

        private Random _rand = new Random();
        private ActivityType _lastActivityType = ActivityType.Break;

        private Dictionary<ActivityType, List<int>> _unselectedActivities = null;
        private Dictionary<ActivityType, List<int>> UnselectedActivities
        {
            get
            {
                if (_unselectedActivities == null)
                    Initialize();
                return _unselectedActivities;
            }
        }

        private Dictionary<ActivityType, List<Activity>> _typedActivities = null;
        private Dictionary<ActivityType, List<Activity>> TypedActivities
        {
            get
            {
                if (_typedActivities == null)
                    Initialize();
                return _typedActivities;
            }
        }

        private void Initialize()
        {
            _typedActivities = new Dictionary<ActivityType, List<Activity>>();
            _unselectedActivities = new Dictionary<ActivityType, List<int>>();            

            var types = Enum.GetValues(typeof(ActivityType));
            foreach (var type in types)
            {
                _typedActivities.Add((ActivityType)type, new List<Activity>());
                _unselectedActivities.Add((ActivityType)type, new List<int>());                
            }

            foreach (var activity in activities)
            {
                _typedActivities[activity.activityType].Add(activity);

                var activityIndex = _typedActivities[activity.activityType].Count - 1;
                _unselectedActivities[activity.activityType].Add(activityIndex);
            }
        }

        /// <summary>
        /// Gets a random activity that hasn't been shown yet. Avoids picking a break if the last one was a break.
        /// </summary>
        public Activity GetNextActivity()
        {
            var typeCount = UnselectedActivities.Count;

            ActivityType selectedType;            
            bool selectedTypeIsBad = false;
            int attempts = 0;

            do
            {
                selectedType = (ActivityType)_rand.Next(typeCount);
                attempts++;
                selectedTypeIsBad = (_lastActivityType == ActivityType.Break && selectedType == ActivityType.Break) 
                                        || UnselectedActivities[selectedType].Count == 0;
            } while (selectedTypeIsBad && attempts < 100);    
            
            if (attempts >= 100)
            {
                Initialize();
                return GetNextActivity();
            }  

            return GetNextActivity(selectedType);
        }

        /// <summary>
        /// Gets a random activity of the specified type that hasn't been shown yet.
        /// </summary>
        private Activity GetNextActivity(ActivityType type)
        {
            _lastActivityType = type;
            var unselectedIndex = _rand.Next(UnselectedActivities[type].Count);
            var selectedIndex = UnselectedActivities[type][unselectedIndex];
            var selectedActivity = TypedActivities[type][selectedIndex];
            UnselectedActivities[type].Remove(selectedIndex);
            return selectedActivity;
        }

        public Activity GetLongestActivityByType(ActivityType type)
        {
            var maxLength = 0;
            Activity longestActivity = null;

            foreach (var activity in activities)
            {
                if (activity.activityType == type && activity.text.Length > maxLength)
                {
                    maxLength = activity.text.Length;
                    longestActivity = activity;
                }
            }

            return longestActivity;
        }

        public Activity GetShortestActivityByType(ActivityType type)
        {
            var minLength = 1000;
            Activity shortestActivity = null;

            foreach (var activity in activities)
            {
                if (activity.activityType == type && activity.text.Length < minLength)
                {
                    minLength = activity.text.Length;
                    shortestActivity = activity;
                }
            }

            return shortestActivity;
        }

        public Activity GetActivityWithFollowup()
        {
            foreach (var activity in activities)
            {
                if (!string.IsNullOrEmpty(activity.followup))
                {
                    return activity;
                }
            }

            throw new Exception("No activity found that had a followup value");
        }

        public Activity GetActivityWithoutFollowup()
        {
            foreach (var activity in activities)
            {
                if (string.IsNullOrEmpty(activity.followup))
                {
                    return activity;
                }
            }

            throw new Exception("No activity found that didn't have a followup value");
        }


    }
}
