using System;
using System.Collections.Generic;
using Sirenix.OdinInspector;
using UnityEngine;
using VOID.Generic.Dict;

namespace VOID.Generic.World
{
    public class Area : MonoBehaviour
    {
        #region GIZMOS

        private void OnDrawGizmos()
        {
            var defaultColor = Gizmos.color;
            var forward = transform.forward;
            var right = transform.right;
            var back = -forward;
            var left = -right;
            
            if (forwardConnection.type != AreaConnectionType.Inner)
            {
                GizmosDrawBorder(left, forward, right, forwardConnection);
                GizmosDrawPassage(left, forward, right, forwardConnection);
            }

            if (rightConnection.type != AreaConnectionType.Inner)
            {
                GizmosDrawBorder(forward, right, back, rightConnection);
                GizmosDrawPassage(forward, right, back, rightConnection);
            }

            if (backConnection.type != AreaConnectionType.Inner)
            {
                GizmosDrawBorder(right, back, left, backConnection);
                GizmosDrawPassage(right, back, left, backConnection);
            }

            if (leftConnection.type != AreaConnectionType.Inner)
            {
                GizmosDrawBorder(back, left, forward, leftConnection);
                GizmosDrawPassage(back, left, forward, leftConnection);
            }
            Gizmos.color = defaultColor;
        }

        private void GizmosDrawBorder(Vector3 left, Vector3 forward, Vector3 right, AreaConnection connection)
        {
            if (connection.type == AreaConnectionType.Inner) return;
            var areaPos = transform.position;
            var floor = Vector3.up * HeightPerFloor * connection.floor;
            Gizmos.color = Color.red;
            Gizmos.DrawLine(
                areaPos + floor + forward * Size / 2 + left * Size / 2,
                areaPos + floor + forward * Size / 2 + right * Size / 2
            );
        }

        private void GizmosDrawPassage(Vector3 left, Vector3 forward, Vector3 right, AreaConnection connection)
        {
            float passageWidth;
            switch (connection.type)
            {
                case AreaConnectionType.Tunnel: passageWidth = 5f; break;
                case AreaConnectionType.Whole: passageWidth = Size - 1f; break;
                case AreaConnectionType.None:
                case AreaConnectionType.Inner:
                default: return;
            }
            var areaPos = transform.position;
            var floor = Vector3.up * HeightPerFloor * connection.floor;
            var passageHeight = Vector3.up * 5f;

            Gizmos.color = Color.blue;
            Gizmos.DrawLineStrip(new []{
                areaPos + floor + forward * Size / 2 + left * passageWidth / 2,
                areaPos + floor + forward * Size / 2 + right * passageWidth / 2,
                areaPos + floor + passageHeight + forward * Size / 2 + right * passageWidth / 2,
                areaPos + floor + passageHeight + forward * Size / 2 + left * passageWidth / 2
            }, true);
        }

        #endregion
        
        [BoxGroup("Constant Variables")]
        [HorizontalGroup("Constant Variables/Row")]
        [ShowInInspector]
        [ReadOnly]
        [InfoBox("Constant size of single square area. Content of this area SHOULD NOT leave given bounds.")]
        public const float Size = 50f;
        
        [BoxGroup("Constant Variables")]
        [HorizontalGroup("Constant Variables/Row")]
        [ShowInInspector]
        [ReadOnly]
        [InfoBox("Constant height of floor. Every floor supposed to be dividable by that value.")]
        public const float HeightPerFloor = 3f;

        [BoxGroup("Complex Area")]
        [HorizontalGroup("Complex Area/Row")]
        [ReadOnly]
        [InfoBox(nameof(ComplexArea) + " which is current " + nameof(Area) + "'s parent. It is filled by button in " + nameof(ComplexArea))]
        [DontValidate]
        public ComplexArea complexArea;
        
        [BoxGroup("Complex Area")]
        [HorizontalGroup("Complex Area/Row")]
        [ReadOnly]
        [InfoBox("Position relative to the " + nameof(ComplexArea) + ". Usable only from " + nameof(ComplexArea))]
        public Vector2Int position = Vector2Int.zero;

        [InfoBox("Connections to other areas."
                 +"\nInner connection cant be edited here, check " + nameof(ComplexArea) + "."
                 +"\nConnection only with matching tags can be connected.")]
        [BoxGroup("Connections")]
        public AreaConnection forwardConnection = new();
        [BoxGroup("Connections")]
        public AreaConnection rightConnection = new();
        [BoxGroup("Connections")]
        public AreaConnection backConnection = new();
        [BoxGroup("Connections")]
        public AreaConnection leftConnection = new();

        public List<AreaConnection> GetConnections() =>
            new() { forwardConnection, rightConnection, backConnection, leftConnection };

        public AreaConnection GetConnection(Direction2D direction) => direction switch
        {
            Direction2D.Forward => forwardConnection,
            Direction2D.Right => rightConnection,
            Direction2D.Back => backConnection,
            Direction2D.Left => leftConnection,
            _ => throw new ArgumentOutOfRangeException(nameof(direction), direction, null)
        };
    }
}