using System.Collections.Generic;
using Fusion.Analyzer;
using UnityEngine;
namespace Fusion {
  
  #if UNITY_EDITOR
  using UnityEditor;
  #endif
  /// 
  /// Automatically adds a  for each indicated component. 
  /// These indicated components will be limited to no more than one enabled instance when running in Multi-Peer mode.
  /// 
  [AddComponentMenu("Fusion/Enable On Single Runner")]
  public class EnableOnSingleRunner : Fusion.Behaviour {
    /// 
    /// If more than one runner instance is visible, this indicates which peer's clone of this entity should be visible.
    /// 
    [InlineHelp]
    [SerializeField]
#pragma warning disable IDE0044 // Add readonly modifier
    public RunnerVisibilityLink.PreferredRunners PreferredRunner;
#pragma warning restore IDE0044 // Add readonly modifier
    /// 
    /// Collection of components that will be marked for Multi-Peer mode as objects that should only have one enabled instance.
    /// 
    [InlineHelp]
    public UnityEngine.Component[] Components = new Component[0];
    /// 
    /// Prefix for the GUIDs of  components which are added at runtime.
    /// 
    [HideInInspector]
    [SerializeField]
    private string _guid = System.Guid.NewGuid().ToString().Substring(0, 19);
    /// 
    /// At runtime startup, this adds a  for each component reference to this GameObject.
    /// 
    internal void AddNodes(List existingNodes) {
      for(int i = 0; i < Components.Length; ++i) {
        var found = false;
        foreach (var existingNode in existingNodes) {
          if (existingNode.Component == Components[i]) {
            found = true;
            break;
          }
        }
        
        if (found) continue;
        var node = Components[i].gameObject.AddComponent();
        node.Guid = _guid + i;
        node.Component = Components[i];
        node.SetupOnSingleRunnerLink(PreferredRunner);
        existingNodes.Add(node);
      }
    }
    /// 
    /// Finds visual/audio components on this GameObject, and adds them to the Components collection.
    /// 
    [EditorButton("Find on GameObject", EditorButtonVisibility.EditMode, dirtyObject: true)]
    public void FindRecognizedTypes() {
      Components = FindRecognizedComponentsOnGameObject(gameObject);
    }
    /// 
    /// Finds visual/audio nested components on this GameObject and its children, and adds them to the Components collection.
    /// 
    [EditorButton("Find in Nested Children", EditorButtonVisibility.EditMode, dirtyObject: true)]
    public void FindNestedRecognizedTypes() {
      Components = FindRecognizedNestedComponents(gameObject);
    }
    [StaticField(StaticFieldResetMode.None)]
    private static readonly List reusableComponentsList = new List();
    [StaticField(StaticFieldResetMode.None)]
    private static readonly List reusableComponentsList2 = new List();
    private static Component[] FindRecognizedComponentsOnGameObject(GameObject go) {
      try {
        go.GetComponents(reusableComponentsList);
        reusableComponentsList2.Clear();
        foreach (var comp in reusableComponentsList) {
          var type = comp.GetType();
          if (type.IsRecognizedByRunnerVisibility()) {
            reusableComponentsList2.Add(comp);
          }
        }
        return reusableComponentsList2.ToArray();
      } finally {
        reusableComponentsList.Clear();
        reusableComponentsList2.Clear();
      }
    }
    private static Component[] FindRecognizedNestedComponents(GameObject go) {
      try {
        go.transform.GetNestedComponentsInChildren(reusableComponentsList, true);
        reusableComponentsList2.Clear();
        foreach (var comp in reusableComponentsList) {
          var type = comp.GetType();
          if (type.IsRecognizedByRunnerVisibility()) {
            reusableComponentsList2.Add(comp);
          }
        }
        return reusableComponentsList2.ToArray();
      } finally {
        reusableComponentsList.Clear();
        reusableComponentsList2.Clear();
      }
    }
  }
}