using UnityEngine;
using UnityEditor;
using UnityEditor.SceneManagement;

namespace VolumetricFogAndMist2 {

    public partial class VolumetricFogEditor {

        bool mouseIsDown;

        private void OnSceneGUI() {

            Event e = Event.current;
            if (fog == null || !fog.enableFogOfWar || !maskEditorEnabled.boolValue || e == null || fog.fogOfWarTexture == null) {
                return;
            }

            Camera sceneCamera = null;
            SceneView sceneView = SceneView.lastActiveSceneView;
            if (sceneView != null) sceneCamera = sceneView.camera;
            if (sceneCamera == null) return;

            Vector2 mousePos = Event.current.mousePosition;
            if (mousePos.x < 0 || mousePos.x > sceneCamera.pixelWidth || mousePos.y < 0 || mousePos.y > sceneCamera.pixelHeight) return;

            Selection.activeGameObject = fog.gameObject;
            fog.UpdateMaterialPropertiesNow();

            Ray ray = HandleUtility.GUIPointToWorldRay(mousePos);
            Bounds bounds = new Bounds(fog.transform.position, new Vector3(fog.transform.lossyScale.x, 0.01f, fog.transform.lossyScale.z));
            if (bounds.IntersectRay(ray, out float distance)) {
                Vector3 hitPoint = ray.origin + ray.direction * distance;
                float handleSize = HandleUtility.GetHandleSize(hitPoint) * 0.5f;
                Handles.color = new Color(0, 0, 1, 0.5f);
                Handles.SphereHandleCap(0, hitPoint, Quaternion.identity, handleSize, EventType.Repaint);
                HandleUtility.Repaint();

                Handles.color = new Color(1, 1, 0, 0.85f);
                Handles.DrawWireDisc(hitPoint, Vector3.up, maskBrushWidth.intValue * 0.995f);
                Handles.color = new Color(0, 0, 1, 0.85f);
                Handles.DrawWireDisc(hitPoint, Vector3.up, maskBrushWidth.intValue);

                if (e.isMouse && e.button == 0) {
                    int controlID = GUIUtility.GetControlID(FocusType.Passive);
                    EventType eventType = e.GetTypeForControl(controlID);

                    if (eventType == EventType.MouseDown) {
                        GUIUtility.hotControl = controlID;
                        mouseIsDown = true;
                    } else if (eventType == EventType.MouseUp) {
                        GUIUtility.hotControl = controlID;
                        mouseIsDown = false;
                    }
                }

                if (mouseIsDown && e.type == EventType.Repaint) {
                    PaintOnMaskPosition(hitPoint);
                }
            }
        }


        #region Mask Texture support functions

        private void CreateNewMaskTexture() {
            int res = Mathf.Clamp(fog.fogOfWarTextureSize, 256, 8192);
            Texture2D tex = new Texture2D(res, res, TextureFormat.RGBA32, false, true);
            tex.wrapMode = TextureWrapMode.Clamp;
            int len = res * res;
            Color32[] cc = new Color32[len];
            Color32 opaque = new Color32(255, 255, 255, 255);
            for (int k = 0; k < cc.Length; k++) {
                cc[k] = opaque;
            }
            tex.SetPixels32(cc);
            tex.Apply();

            string fileName = AssetDatabase.GenerateUniqueAssetPath("Assets/FogOfWarTexture.asset");
            AssetDatabase.CreateAsset(tex, fileName);
            AssetDatabase.SaveAssets();
            fog.fogOfWarTexture = tex;
            fog.maskBrushMode = MASK_TEXTURE_BRUSH_MODE.RemoveFog;
            EditorUtility.SetDirty(fog);
            EditorSceneManager.MarkSceneDirty(UnityEngine.SceneManagement.SceneManager.GetActiveScene());
            EditorGUIUtility.PingObject(tex);
        }

        void PaintOnMaskPosition(Vector3 pos) {
            if (maskBrushMode.intValue == (int)MASK_TEXTURE_BRUSH_MODE.ColorFog) {
                PaintColorOnMaskPosition(pos);
            } else {
                PaintAlphaOnMaskPosition(pos);
            }
        }

        private void PaintAlphaOnMaskPosition(Vector3 pos) {
            // Get texture location
            Color32[] maskColors = fog.fogOfWarTextureData;
            if (maskColors == null) {
                fog.ReloadFogOfWarTexture();
                maskColors = fog.fogOfWarTextureData;
            }
            if (maskColors == null) {
                EditorUtility.DisplayDialog("Fog Of War Editor", "Re-enable fog of war to create the underline texture.", "Ok");
                return;
            }
            Vector3 fogOfWarCenter = fog.anchoredFogOfWarCenter;
            float x = (pos.x - fogOfWarCenter.x) / fog.fogOfWarSize.x + 0.5f;
            float z = (pos.z - fogOfWarCenter.z) / fog.fogOfWarSize.z + 0.5f;
            int textureSize = fog.fogOfWarTextureSize;
            int tx = Mathf.Clamp((int)(x * textureSize), 0, textureSize - 1);
            int ty = Mathf.Clamp((int)(z * textureSize), 0, textureSize - 1);

            // Prepare brush data
            int brushSize = Mathf.FloorToInt(fog.fogOfWarTextureSize * maskBrushWidth.intValue / fog.fogOfWarSize.x);
            byte color = maskBrushMode.intValue == (int)MASK_TEXTURE_BRUSH_MODE.AddFog ? (byte)255 : (byte)0;
            float brushOpacity = 1f - maskBrushOpacity.floatValue * 0.2f;
            float fuzziness = 1.1f - maskBrushFuzziness.floatValue;
            byte colort = (byte)(color * (1f - brushOpacity));
            float radiusSqr = brushSize * brushSize;
            // Paint!
            for (int j = ty - brushSize; j < ty + brushSize; j++) {
                if (j < 0) continue; else if (j >= textureSize) break;
                int jj = j * textureSize;
                int dj = (j - ty) * (j - ty);
                for (int k = tx - brushSize; k < tx + brushSize; k++) {
                    if (k < 0) continue; else if (k >= textureSize) break;
                    int distSqr = dj + (k - tx) * (k - tx);
                    float op = distSqr / radiusSqr;
                    float threshold = UnityEngine.Random.value;
                    if (op <= 1f && threshold * op < fuzziness) {
                        maskColors[jj + k].a = (byte)(colort + maskColors[jj + k].a * brushOpacity);
                    }
                }
            }
            fog.UpdateFogOfWar(true);
        }


        private void PaintColorOnMaskPosition(Vector3 pos) {
            // Get texture location
            Color32[] maskColors = fog.fogOfWarTextureData;
            if (maskColors == null) {
                fog.ReloadFogOfWarTexture();
                maskColors = fog.fogOfWarTextureData;
            }
            if (maskColors == null) {
                EditorUtility.DisplayDialog("Fog Of War Editor", "Re-enable fog of war to create the underline texture.", "Ok");
                return;
            }
            Vector3 fogOfWarCenter = fog.anchoredFogOfWarCenter;
            float x = (pos.x - fogOfWarCenter.x) / fog.fogOfWarSize.x + 0.5f;
            float z = (pos.z - fogOfWarCenter.z) / fog.fogOfWarSize.z + 0.5f;
            int textureSize = fog.fogOfWarTextureSize;
            int tx = Mathf.Clamp((int)(x * textureSize), 0, textureSize - 1);
            int ty = Mathf.Clamp((int)(z * textureSize), 0, textureSize - 1);

            // Prepare brush data
            int brushSize = Mathf.FloorToInt(fog.fogOfWarTextureSize * maskBrushWidth.intValue / fog.fogOfWarSize.x);
            float brushOpacity = 1f - maskBrushOpacity.floatValue * 0.2f;
            float fuzziness = 1.1f - maskBrushFuzziness.floatValue;
            byte rt = (byte)(maskBrushColor.colorValue.r * (1f - brushOpacity) * 255f);
            byte gt = (byte)(maskBrushColor.colorValue.g * (1f - brushOpacity) * 255f);
            byte bt = (byte)(maskBrushColor.colorValue.b * (1f - brushOpacity) * 255f);
            Color32 colort = new Color32(rt, gt, bt, 255);
            float radiusSqr = brushSize * brushSize;
            // Paint!
            for (int j = ty - brushSize; j < ty + brushSize; j++) {
                if (j < 0) continue; else if (j >= textureSize) break;
                int jj = j * textureSize;
                int dj = (j - ty) * (j - ty);
                for (int k = tx - brushSize; k < tx + brushSize; k++) {
                    if (k < 0) continue; else if (k >= textureSize) break;
                    int distSqr = dj + (k - tx) * (k - tx);
                    float op = distSqr / radiusSqr;
                    float threshold = UnityEngine.Random.value;
                    if (op <= 1f && threshold * op < fuzziness) {
                        maskColors[jj + k].r = (byte)(colort.r + maskColors[jj + k].r * brushOpacity);
                        maskColors[jj + k].g = (byte)(colort.g + maskColors[jj + k].g * brushOpacity);
                        maskColors[jj + k].b = (byte)(colort.b + maskColors[jj + k].b * brushOpacity);
                    }
                }
            }
            fog.UpdateFogOfWar(true);
        }


        #endregion

    }

}