using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Assets.Scripts.Core;
using Assets.Scripts.UI;

namespace Assets.Scripts.Events
{
    public class GameEvent {
        public delegate void NodeEffect(ICore core);
        public delegate string GetText(PlayerStats stats);
        public delegate bool Condition(PlayerStats stats);

        public class Option {
            public GetText Label { get; private set; }
            public Node NextNode { get; set; }
            public Condition Condition { get; set; }

            public Option (string label)
                : this(p => label) { }

            public Option (GetText label) {
                Label = label;
                Condition = p => true;
            }
        }

        public class Node {
            public GetText Description;
            public Option[] Options;
            public NodeEffect Effect;
            public NodeEffect PostEffect;
            public Node AfterResume;

            public Node (string description, params Option[] options)
                : this(p => description, options) {}

            public Node (GetText description, params Option[] options) {
                Description = description;
                Options = options.Length > 0 ? options : null;
            }
        }

        private IEventUI _ui;
        private ICore _gameCore;
        private readonly Node _initialNode;
        private Node _node;

        public GameEvent(Node node) {
            _initialNode = node;
        }

        public void StartEvent(ICore gameCore, IEventUI ui) {
            _ui = ui;
            _gameCore = gameCore;
            _node = _initialNode;
            ActivateCurrentNode();
        }

        public void ResumeEvent () {
            ActivateCurrentNode();
        }

        private void ActivateCurrentNode() {
            ProcessNodeEffects(_node);
            ShowNode(_node);
        }

        private void ProcessNodeEffects(Node node) {
            if (node.Effect != null) {
                node.Effect(_gameCore);
            }
        }

        private void ShowNode(Node node) {
            var stats = _gameCore.PlayerStats;
            _ui.ShowText(node.Description(stats));
            if (node.Options == null) {
                ShowDefaultOption();
            } else {
                //var validOptions = node.Options.Where(o => o.Condition(stats)).ToArray();
                var validOptions = node.Options;
                if (validOptions.Length > 0) {
                    _ui.ShowOptions(validOptions.Select(o => (o.Condition(stats) ? "" : "N/A: ") + o.Label(stats)).ToArray(), n => OnEventOption(validOptions[n]));
                } else {
                    ShowDefaultOption();
                }
            }
        }

        private void ShowDefaultOption() {
            _ui.ShowOptions(new[] {"Done"}, n => EndEvent());
        }

        private void OnEventOption(Option option) {
            if (option.NextNode != null) {
                _node = option.NextNode;
                ActivateCurrentNode();
            } else {
                EndEvent();
            }
        }

        private void EndEvent() {
            bool hasResume = _node != null && _node.AfterResume != null;

            if (!hasResume) {
                _gameCore.EndEvent();
            }

            if (_node != null && _node.PostEffect != null) {
                _node.PostEffect(_gameCore);
            }

            if (hasResume) {
                _node = _node.AfterResume;
                _gameCore.SuspendEvent();
            }
        }

        public string Id { get; set; }
        public bool Recurring { get; set; }
        public Condition TriggerCondition { get; set; }

        public bool CanTrigger(PlayerStats playerStats) {
            return TriggerCondition == null || TriggerCondition(playerStats);
        }
    }
}
