using UnityEngine;
using UnityEditor.EditorTools;
using UnityEditor;

[EditorTool("Light Placement Tool", typeof(Light))]
class LightPlacementTool : EditorTool
{
    private const float k_DefaultZoom = 0.05f;
    private bool initialPositionSet;

    private static Vector3 initialPivot;
    private static Quaternion initialRotation;

    private static Vector3 originalPivot;
    private static Quaternion originalRotation;

    private static GameObject currentGameObject;
    private float previousZoom;
    private static SceneView.SceneViewState previousSceneViewState;
    private static SceneView lastSceneView;

    public override GUIContent toolbarIcon => EditorGUIUtility.TrIconContent(UnityEditor.Rendering.CoreEditorUtils.LoadIcon(@"Packages/com.unity.render-pipelines.core/Editor/Lighting/Icons/", "LightPlacement_Icon", ".png", false), "The Light Placement Tool temporarily changes the Scene Camera to look-through the currently selected Light. Use the Scene View Navigation controls to move it around the Scene.");

    public override void OnActivated()
    {
        base.OnActivated();
        if (lastSceneView == null)
        {
            lastSceneView = SceneView.lastActiveSceneView;
            lastSceneView.orthographic = false;
            previousSceneViewState = lastSceneView.sceneViewState;
            lastSceneView.sceneViewState.alwaysRefresh = true;
        }
        TransitionCameraToLight();
        Undo.undoRedoPerformed += OnUndoRedo;
    }

    public override void OnWillBeDeactivated()
    {
        base.OnWillBeDeactivated();
        if (lastSceneView != null)
        {
            lastSceneView.sceneViewState = previousSceneViewState;
        }
        Undo.undoRedoPerformed -= OnUndoRedo;
        ResetCamera();
    }

    public override void OnToolGUI(EditorWindow window)
    {
        base.OnToolGUI(window);
        SceneView view = SceneView.lastActiveSceneView;

        //View size getting smaller than 0.0001f causes the camera to get stuck
        if (view.size <= 0)
            view.FixNegativeSize();

        if (lastSceneView != view)
            return;

        if (currentGameObject == null)
            return;

        if (!initialPositionSet)
        {
            SetInitialPosition(view);
            return;
        }

        Event e = Event.current;

        if (e.type == EventType.KeyDown && e.keyCode == KeyCode.Escape)
        {
            ToolManager.RestorePreviousTool();
            e.Use();
            view.Repaint();
            return;
        }

        Undo.RecordObject(currentGameObject.transform, "Move Light");
        Vector3 lookDir = (view.pivot - view.camera.transform.position).normalized;
        currentGameObject.transform.SetPositionAndRotation(view.camera.transform.position + lookDir * k_DefaultZoom * 2f, view.camera.transform.rotation);
    }

    private void OnUndoRedo()
    {
        if (currentGameObject != null && lastSceneView != null)
        {
            lastSceneView.pivot = currentGameObject.transform.position;
            lastSceneView.rotation = currentGameObject.transform.rotation;
        }
    }

    private void TransitionCameraToLight()
    {
        initialPivot = SceneView.lastActiveSceneView.pivot;
        initialRotation = SceneView.lastActiveSceneView.camera.transform.rotation;

        var targetComponent = target as Light;
        if (targetComponent != null)
        {
            currentGameObject = targetComponent.gameObject;
            originalPivot = currentGameObject.transform.position;
            originalRotation = currentGameObject.transform.rotation;
            initialPositionSet = false;
        }
    }

    private void SetInitialPosition(SceneView view)
    {
        previousZoom = view.size;
        view.pivot = originalPivot;
        view.rotation = originalRotation;
        view.size = k_DefaultZoom;
        view.Repaint();
        initialPositionSet = true;
    }

    private void ResetCamera()
    {
        SceneView.lastActiveSceneView.pivot = initialPivot;
        SceneView.lastActiveSceneView.rotation = initialRotation;
        SceneView.lastActiveSceneView.size = previousZoom;
    }
}