using SanAndreasUnity.Behaviours.World;
using SanAndreasUnity.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;

namespace SanAndreasUnity.Editor
{
    public class WaterMenuTools
    {
        private const string WaterMenuItemPrefix = EditorCore.MenuName + "/Water/";


        static void DisplayMessage(string msg)
        {
            EditorUtility.DisplayDialog("", msg, "Ok");
        }

        static Water GetWaterOrShowMessage()
        {
            if (null == Cell.Singleton || null == Cell.Singleton.Water)
            {
                DisplayMessage("Water object not found");
                return null;
            }

            return Cell.Singleton.Water;
        }

        static void SetSelection(GameObject[] objects)
        {
            Selection.objects = objects;
            if (objects.Length > 0)
                EditorGUIUtility.PingObject(objects[0]);
        }

        [MenuItem(WaterMenuItemPrefix + "Initialize water")]
        static void InitWater()
        {
            var water = GetWaterOrShowMessage();
            if (null == water)
                return;

            water.Initialize(Vector2.one * Cell.Singleton.WorldSize);
        }

        [MenuItem(WaterMenuItemPrefix + "Remove water")]
        static void RemoveWater()
        {
            var water = GetWaterOrShowMessage();
            if (null == water)
                return;

            water.transform.GetFirstLevelChildrenPreallocated().ForEach(_ => UnityEngine.Object.DestroyImmediate(_.gameObject));
        }

        [MenuItem(WaterMenuItemPrefix + "Select water faces with non-4 vertices")]
        static void SelectNon4WaterFaces()
        {
            var water = GetWaterOrShowMessage();
            if (null == water)
                return;

            var waterFaceInfos = water
                .GetComponentsInChildren<WaterFaceInfo>()
                .Where(_ => _.WaterFace.Vertices.Length != 4)
                .Select(_ => _.gameObject)
                .ToArray();

            SetSelection(waterFaceInfos);
        }

        [MenuItem(WaterMenuItemPrefix + "Select shallow water faces")]
        static void SelectShallowWaterFaces()
        {
            var water = GetWaterOrShowMessage();
            if (null == water)
                return;

            var waterFaceInfos = water
                .GetComponentsInChildren<WaterFaceInfo>()
                .Where(_ => (_.WaterFace.Flags & Importing.Items.Placements.WaterFlags.Shallow) != 0)
                .Select(_ => _.gameObject)
                .ToArray();

            SetSelection(waterFaceInfos);
        }

        [MenuItem(WaterMenuItemPrefix + "Select water faces in interiors")]
        static void SelectWaterFacesInInteriors()
        {
            var water = GetWaterOrShowMessage();
            if (null == water)
                return;

            var waterFaceInfos = water
                .GetComponentsInChildren<WaterFaceInfo>()
                .Where(_ => _.transform.localPosition.y > 500f)
                .Select(_ => _.gameObject)
                .ToArray();

            SetSelection(waterFaceInfos);
        }

        [MenuItem(WaterMenuItemPrefix + "Select water face by camera raycast")]
        static void SelectWaterFaceByCameraRaycast()
        {
            var cam = SceneView.lastActiveSceneView != null
                ? SceneView.lastActiveSceneView.camera
                : null;

            if (null == cam)
            {
                DisplayMessage("Failed to find SceneView camera");
                return;
            }

            if (!Physics.Raycast(cam.transform.position, cam.transform.forward, out var hit, 10000f, Water.LayerMask, QueryTriggerInteraction.Collide))
                return;

            if (hit.transform.GetComponent<WaterFaceInfo>() == null)
                return;

            SetSelection(new GameObject[] { hit.transform.gameObject });
        }

        [MenuItem(WaterMenuItemPrefix + "Test collision against ground beneath")]
        static void TestCollision()
        {
            var water = GetWaterOrShowMessage();
            if (null == water)
                return;

            var waterFaceInfos = water.GetComponentsInChildren<WaterFaceInfo>();

            var collidingFaces = new List<GameObject>();

            foreach (var waterFaceInfo in waterFaceInfos)
            {
                var boxCollider = waterFaceInfo.GetComponentOrThrow<BoxCollider>();
                if (Physics.CheckBox(
                    waterFaceInfo.transform.position.WithAddedY(-10f),
                    boxCollider.size * 0.5f,
                    waterFaceInfo.transform.rotation,
                    Behaviours.GameManager.DefaultLayerMask,
                    QueryTriggerInteraction.Collide))
                    collidingFaces.Add(waterFaceInfo.gameObject);
            }

            if (collidingFaces.Count > 0)
                SetSelection(collidingFaces.ToArray());
        }
    }
}