using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Profiling;

namespace Ingvar.LiveWatch
{
    public class WatchVariableUpdater
    {
        public static string ErrorValue = "ERROR";
        
        public bool AnyPushSinceUpdate { get; set; }
        public bool IsUpdatingNow { get; private set; }
        public int ValuesCount { get; private set; }
        
        public void UpdateAll()
        {
            if (!Watch.IsLive)
                return;
            
            Profiler.BeginSample("Watch update all");

            IsUpdatingNow = true;
            
            foreach (var watch in Watch.Watches.Items)
                Update(watch.Value);
            
            foreach (var watch in Watch.Watches.Items)
                PostUpdate(watch.Value);
            
            IsUpdatingNow = false;
            AnyPushSinceUpdate = false;
            
            Profiler.EndSample();
        }

        private void Update(WatchVariable watchVariable)
        {
            if (watchVariable == null)
            {
                return;
            }
            
            
            if (watchVariable.RuntimeMeta.UpdateCall != null)
            {
                try
                {
                    watchVariable.RuntimeMeta.UpdateCall();
                }
                catch                {
                    if (watchVariable.Values.Type == WatchValueType.String)
                        watchVariable.Values.StringList.Add(new WatchValue<string>(ErrorValue));
                    else 
                        watchVariable.Values.PushEmpty();
                    
                }
            }
            
            foreach (var child in watchVariable.Childs.Items)
            {
                Update(child.Value);
            }
            
            watchVariable.RuntimeMeta.IsUpdatedAtLeastOnce = true;
        }

        private void PostUpdate(WatchVariable watchVariable)
        {
            if (watchVariable == null)
            {
                return;
            }

            CatchUpWithValuesCount(watchVariable, ValuesCount);
            
            foreach (var child in watchVariable.Childs.Items)
            {
                PostUpdate(child.Value);
            }
        }
        
        public void ClearAll()
        {
            foreach (var watch in Watch.Watches.Items)
            {
                Clear(watch.Value, true);
            }

            ValuesCount = 0;
        }

        public void Clear(WatchVariable watchVariable, bool recursive = true)
        {
            watchVariable.Values.Clear();
            
            watchVariable.EditorMeta.LastNonShrinkableIndexOfKey = -1;
            watchVariable.EditorMeta.LastStringToNumberValue = -1;

            if (recursive && watchVariable.HasChilds)
            {
                foreach (var child in watchVariable.Childs.Items)
                {
                    Clear(child.Value);
                }
            }
        }

        public void UpdateTotalValuesCount(WatchVariable variable)
        {
            ValuesCount = Mathf.Max(ValuesCount, variable.Values.Count);
        }
        
        public void CatchUpWithValuesCount(WatchVariable variable, int valuesCount)
        {

            if (valuesCount <= 0
                || variable.Values.Count >= valuesCount)
                return;
                
            if (variable.Values.Count == 0)
                variable.Values.PushEmpty();
                
            variable.Values.Expand(valuesCount - variable.Values.Count);
        }
    }
}