using System.Collections;
using Intrepid.Core.Camera.Events;
using Intrepid.SimpleEvents;
using Intrepid.Utilities;
using Unity.Cinemachine;
using UnityEngine;

namespace Intrepid.Core.Camera
{
    public class CameraSystem : SingletonEventListener<CameraSystem>
    {
        [GroupInjections, SerializeField] private UnityEngine.Camera mainCamera;
        [GroupInjections, SerializeField] private CinemachineBrain cinemachineBrain;
        [GroupInjections, SerializeField] private CameraBoundaryManager cameraBoundaryManager;

        private bool IsBlendClearing { get; set; }
        public CameraStreamStack CurrentCameraStreamStack { get; private set; }
        public bool IsCameraBlending => cinemachineBrain.IsBlending;
        public float NormalAngle => mainCamera.transform.rotation.eulerAngles.z;
        public UnityEngine.Camera MainCamera => mainCamera;
        public CameraBoundaryManager CameraBoundaryManager => cameraBoundaryManager;

        public Vector3 CameraTargetPosition =>
            CurrentCameraStreamStack?.TopCameraStream?.VCamera.Follow.position ?? Vector3.zero;

        protected override void InitializeVariables()
        {
            SingletonInstantiation(false, _ => { });
        }

        protected override void OnBootstrap()
        {
        }

        protected override void Subscriptions()
        {
            Subscribe<CameraStreamChangeEvent>(e =>
            {
                CurrentCameraStreamStack?.Disable();
                CurrentCameraStreamStack = e.CameraStreamStack;
                CurrentCameraStreamStack.Enable();
            });
        }

        public bool IsRunningInstance(string id)
        {
            return CurrentCameraStreamStack?.TopCameraStream.Id.Equals(id) ?? false;
        }

        private void LateUpdate()
        {
            CurrentCameraStreamStack?.TopCameraStream?.CameraUpdate(CurrentCameraStreamStack?.TopCameraStream);
        }

        public void ForceFocusOn(Vector3 position)
        {
            if (IsBlendClearing) return;
            StartCoroutine(StraightMoveCameraPosition(position));
        }

        private IEnumerator StraightMoveCameraPosition(Vector3 position)
        {
            IsBlendClearing = true;

            yield return null;

            CurrentCameraStreamStack?.TopCameraStream.VCamera.gameObject.SetActive(false);
            cinemachineBrain.enabled = false;

            yield return null;

            mainCamera.transform.position = position;
            cinemachineBrain.transform.position = position;

            if (CurrentCameraStreamStack is not null)
            {
                CurrentCameraStreamStack.TopCameraStream.VCamera.transform.position = position;
            }

            CurrentCameraStreamStack?.TopCameraStream.VCamera.gameObject.SetActive(true);
            cinemachineBrain.enabled = true;

            yield return null;

            IsBlendClearing = false;
        }

        public Vector2 ScreenToWorldPoint(Vector2 screenPoint)
        {
            return mainCamera.ScreenToWorldPoint(screenPoint);
        }

        public Vector2 ScreenToViewportPoint(Vector2 screenPoint)
        {
            return mainCamera.ScreenToViewportPoint(screenPoint);
        }
    }
}