using System;
using Ext.B83.Unity.Attributes;
using UnityEngine;
using Random = UnityEngine.Random;

namespace InterfaceOff
{
    [Serializable] public struct SpawnableWindowType
    {
        [field: SerializeField, MonoScript] private string Typename { get; set; }
        public Type Type => Type.GetType(Typename);
        
        [field: SerializeField] public int SpawnWeight { get; private set; }
    }

    public class WindowSpawner : MonoBehaviour
    {
        [field: SerializeField] private GameObject SampleChild { get; set; }
        [field: SerializeField] private Canvas GameCanvas { get; set; }

        [field: SerializeField] private SpawnableWindowType[] WindowTypes { get; set; }
        private int TotalSpawnWeight { get; set; }

        [field: SerializeField] public bool AutoSpawn { get; private set; } = true;
        private int SpawnCounter { get; set; }

        private void Awake()
        {
            /* Logs the amount of types found and errors if there is none */
            Debug.Log($"Found [{WindowTypes.Length}] different window types ");
            if (WindowTypes.Length == 0)
            {
                Debug.LogError("Could not find any window types");
                return;
            }
            
            /* Calculates the total spawn weight */
            TotalSpawnWeight = 0;
            foreach (SpawnableWindowType type in WindowTypes)
            {
                TotalSpawnWeight += type.SpawnWeight;
            }
        }

        private Type GetRandomWindowType()
        {
            int currentTypeWeight = Random.Range(0, TotalSpawnWeight);
            foreach (SpawnableWindowType type in WindowTypes)
            {
                currentTypeWeight -= type.SpawnWeight;
                if (currentTypeWeight <= 0)
                {
                    return type.Type;
                }
            }

            return WindowTypes[0].Type;
        }

        private void SpawnNewRandomWindow()
        {
            /* Creates the gameobject with a random class */
            GameObject go = Instantiate(SampleChild, GameCanvas.transform);
            go.SetActive(true);

            Type type = GetRandomWindowType();
            go.name = type.Name;
            
            WindowBase windowBase = go.AddComponent(type) as WindowBase;

            /* Checks it created correctly before instantiating further */
            if (DebugUtils.IsNull(windowBase))
            {
                Debug.LogError("How did this happen");
                return;
            }

            /* Makes sure the WindowInteractions and WindowComponents are setup before passing to user code */
            windowBase.Interactions = go.GetComponent<WindowInteractions>();
            windowBase.Interactions.SetAttachedTo(windowBase);

            windowBase.Components = go.GetComponent<WindowComponents>();
            windowBase.InstantiateWindowBase();
        }

        private void FixedUpdate()
        {
            if (AutoSpawn)
            {
                const int TICKS_PER_SECOND = 20;
                const int MINIMUM_SPAWN_TIME = 2 * 20;
                const int MAXIMUM_SPAWN_TIME = 5 * 20;
                
                /* Decreases the spawn counter and spawns if at 0 */
                SpawnCounter = Math.Max(0, SpawnCounter - 1);
                if (SpawnCounter == 0)
                {
                    SpawnCounter = Random.Range(MINIMUM_SPAWN_TIME, MAXIMUM_SPAWN_TIME);
                    SpawnNewRandomWindow();
                }
            }
        }

        private void Update()
        {
            if (!AutoSpawn)
            {
                if (Input.GetKeyDown(KeyCode.Space))
                {
                    SpawnNewRandomWindow();
                }
            }
        }
    }
}
