using System.Linq;
using StoryEngine.Core.Extensions;
using System.Collections.ObjectModel;
using StoryEngine.Core.HistoryPoints;
using StoryEngine.Extensions;
using Newtonsoft.Json;
using System.Text;
using System;
using System.Collections.Generic;

namespace StoryEngine.Core
{
    public sealed class History
    {
        public string Name { get; set; }
        public ObservableCollection<HistoryPointBase> Points { get; set; } = new ObservableCollection<HistoryPointBase>();
        public string CurrentPointId { get; set; }
        public HistoryPointBase GetCurrentPoint() => CurrentPointId != null
            ? Points.First(p => p.Id == CurrentPointId)
            : null;

        [JsonIgnore]
        public Variables Variables { get; set; } = new Variables();

        [JsonIgnore]
        public string DebugInfo { get; set; }

        private Dictionary<string, Action<int>> _setters = new Dictionary<string, Action<int>>();
        
        public void Step(int variantIndex)
        {
            var sb = new StringBuilder();
            if (variantIndex > -1)
            {
                var selected = GetCurrentPoint().Variants[variantIndex];
                foreach (var modifier in selected.Modifiers)
                {
                    modifier.Execute(this);
                    if (_setters.TryGetValue(modifier.VariableName, out var setter))
                        setter.Invoke(Variables[modifier.VariableName]);
                    sb.AppendLine($"// {modifier.VariableName} = {Variables[modifier.VariableName]}");
                }
            }
            DebugInfo = sb.ToString();
            var possiblePoints = Points.InnerJoin(GetCurrentPoint().NextPossiblePoints, (p, id) => p.Id == id);
            foreach (var point in possiblePoints)
            {
                if (point.Filters.All(f => f.Execute(this)))
                {
                    CurrentPointId = point.Id;
                    return;
                }
            }
        }

        public string Serialize() => this.ToJson();

        public static History Deserialize(string json) => json.FromJson<History>();

        public History CreateCopy() => Deserialize(Serialize());

        public History WithBinding(string name, int value, Action<int> setter)
        {
            SetBinding(name, value, setter);
            return this;
        }

        private void SetBinding(string name, int value, Action<int> setter)
        {
            Variables[name] = value;
            _setters[name] = setter;
        }
    }
}