using System;
using System.Collections.Generic;
using System.Linq;
using Sirenix.OdinInspector;
using Unity.Cinemachine;
using UnityEngine;

namespace Intrepid.Core.Camera
{
    [Serializable]
    public class CameraStreamStack
    {
        public static readonly PrioritySettings MainPriority = new() { Value = 10, Enabled = true };
        public static readonly PrioritySettings SecondaryPriority = new() { Value = 1, Enabled = true };

        public Transform Transform { get; set; }
        private bool IsOperational { get; set; }
        private Dictionary<string, ICameraStreamUpdatable> CameraStreams { get; } = new();
        [ShowInInspector, ReadOnly] private List<string> Loaded => CameraStreams.Keys.ToList();
        [ShowInInspector, ReadOnly] private Stack<string> Stack { get; } = new();

        public ICameraStreamUpdatable TopCameraStream => CameraStreams[Stack.Peek()];

        public void Enable()
        {
            IsOperational = true;
            TopCameraStream.VCamera.Priority = MainPriority;
        }

        public void Disable()
        {
            IsOperational = false;
            TopCameraStream.VCamera.Priority = SecondaryPriority;
        }
        
        public void Push(ICameraStreamUpdatable cameraStream, bool force = false)
        {
            if (!CameraStreams.TryAdd(cameraStream.Id, cameraStream)) return;
            if(Stack.Count > 0) TopCameraStream.VCamera.Priority = SecondaryPriority;
            Stack.Push(cameraStream.Id);
            if (IsOperational) TopCameraStream.VCamera.Priority = MainPriority;
            if (IsOperational || force) TopCameraStream.VCamera.Follow = Transform;
        }

        public void Pop(string id = null)
        {
            if (CameraStreams.Count - 1 < 1) return;
            if (string.IsNullOrEmpty(id) || id.Equals(Stack.Peek()))
            {
                TopCameraStream.VCamera.Priority = SecondaryPriority;
                CameraStreams.Remove(Stack.Pop());
                while (!CameraStreams.ContainsKey(Stack.Peek()))
                {
                    Stack.Pop();
                }
                if (IsOperational) TopCameraStream.VCamera.Priority = MainPriority;
                return;
            }
            CameraStreams.Remove(id);
        }
    }
}