using CommandUndoRedo;
using UnityEngine;
using UnityEngine.EventSystems;

public class CameraOrbit : MonoBehaviour
{
    public bool LightLock = false;
    public Camera Cam;
    bool controlOn;
    float controlTime;

    [Header("Light")]
    public GameObject Light;
    public GameObject CameraTargetHelper;
    public Vector3 TargetCenter;

    EventSystem eventSystem;

    [Header("Free Camera")]
    bool FreeCamLeft = false;
    bool FreeCamRight = false;
    public Vector3 lookRotation;

    private CameraSettings _settings => ModelViewerMain.GetInstance().GetCameraHandler().Settings;

    private CameraTransformCommand _tempCommand;

    private void Start()
    {
        Init();
    }

    public CameraOrbit Init()
    {
        Cam = GetComponentInChildren<Camera>();
        eventSystem = EventSystem.current;
        return this;
    }

    void Update()
    {
        if (ModelViewerMain.GetInstance() == null) return;
        UpdateImmediate();
    }

    public void UpdateImmediate()
    {
        if (HandleManager.InteractionInProgress || _settings.CameraLock) return;

        switch (_settings.CameraMode)
        {
            case 0:
                OrbitAround();
                OrbitLight();
                break;
            case 1:
                OrbitAround(true);
                OrbitLight();
                break;
            case 2: FreeCamera(); break;
        }
    }

    #region Camera
    /// <summary>
    /// Orbit camera around world center
    /// </summary>
    void OrbitAround(bool aroundCharacter = false)
    {
        float x = 0;
        float y = 0;
        var settings = _settings;

        using (var context = new KeyframeToggleContext(settings))
        {
            if (eventSystem.currentSelectedGameObject == null)
            {
                x = Input.GetAxis("Horizontal");
                y = Input.GetAxis("Vertical");
            }

            if (aroundCharacter)
            {
                var selectedObject = ModelViewerMain.GetInstance().SelectedObject;
                TargetCenter = selectedObject != null ? selectedObject.GetCenter() : Vector3.zero;
            }
            else
            {
                TargetCenter = Vector3.zero;
            }

            Cam.fieldOfView = settings.Fov;
            Vector3 position = transform.position;
            Vector3 rotation = Cam.transform.localEulerAngles;

            if (Input.GetMouseButtonDown(0) && !eventSystem.IsPointerOverGameObject())
            {
                StartKeyframe();
                controlOn = true;
                controlTime = 0;
            }
            if (Input.GetMouseButton(0) && controlOn)
            {
                controlTime += Time.deltaTime;
                position -= Input.GetAxis("Mouse X") * settings.RotSpeed * transform.right;
                settings.SliderCamDist.value -= Input.mouseScrollDelta.y * settings.ZoomSpeed;
                settings.SliderCamHeight.value -= Input.GetAxis("Mouse Y") * settings.RotSpeed;
            }
            else if (controlOn)
            {
                controlOn = false;
                if (controlTime > 0.2f)
                {
                    context.ForceSetKeyframe();
                    EndKeyframe();
                }
            }

            if (Input.GetMouseButtonDown(2) && !eventSystem.IsPointerOverGameObject())
            {
                StartKeyframe();
                CameraTargetHelper.SetActive(true);
                controlTime = 0;
            }
            if (Input.GetMouseButton(2) && CameraTargetHelper.activeSelf)
            {
                controlTime += Time.deltaTime;
                settings.SliderTargetHeight.value -= Input.GetAxis("Mouse Y");
                CameraTargetHelper.transform.position = settings.SliderTargetHeight.value * Vector3.up;
            }
            if (CameraTargetHelper.activeSelf && Input.GetMouseButtonUp(2))
            {
                CameraTargetHelper.SetActive(false);
                if (controlTime > 0.2f)
                {
                    context.ForceSetKeyframe();
                    EndKeyframe();
                }
            }

            float camDist = settings.CamDist;
            settings.SliderCamHeight.maxValue = camDist + 1 - camDist * 0.2f;
            settings.SliderCamHeight.minValue = -camDist + 1 + camDist * 0.2f;
            settings.SliderCamHeight.value += y * settings.RotSpeed;

            Vector3 target = TargetCenter + settings.TargetHeight * Vector3.up; //set target offsets

            position.y = TargetCenter.y + settings.CamHeight; //set camera height
            transform.position = position;  //set final position of camera at target
            transform.position += (x * transform.right) * settings.RotSpeed;

            //Debug.Log(rotation);
            transform.LookAt(target); //look at target position
            Cam.transform.localEulerAngles = settings.CamAngle * Vector3.forward;
            transform.position = target - transform.forward * camDist; //move away from target
            lookRotation = transform.localEulerAngles;
        }
    }

    /// <summary>
    /// Free Camera, Unity-Style
    /// </summary>
    void FreeCamera()
    {
        var settings = _settings; ;
        //Debug.Log("1 " + lookRotation);
        //Debug.Log("2 " + transform.localEulerAngles);
        //Debug.Log("3 " + transform.eulerAngles);
        Cam.fieldOfView = settings.Fov;
        float moveSpeed = settings.MovSpeed;
        float rotateSpeed = settings.RotSpeed;

        if (Input.GetMouseButtonDown(0) && !eventSystem.IsPointerOverGameObject())
        {
            StartKeyframe();
            lookRotation = transform.localEulerAngles;
            FreeCamLeft = true;
            controlTime = 0;
        }
        if (Input.GetMouseButton(0) && FreeCamLeft)
        {
            controlTime += Time.deltaTime;
            transform.position += Input.GetAxis("Vertical") * transform.forward * Time.deltaTime * moveSpeed;
            transform.position += Input.GetAxis("Horizontal") * transform.right * Time.deltaTime * moveSpeed;

            lookRotation.x -= Input.GetAxis("Mouse Y") * rotateSpeed;
            lookRotation.y += Input.GetAxis("Mouse X") * rotateSpeed;

            lookRotation.x = Mathf.Clamp(lookRotation.x, -90, 90);
            if (lookRotation.y >= 360) lookRotation.y -= 360;
            if (lookRotation.y <= -360) lookRotation.y += 360;
            //x (up down) y (left right) changes
            transform.localRotation = Quaternion.Euler(lookRotation.x, lookRotation.y, lookRotation.z);
        }
        else if (FreeCamLeft)
        {
            FreeCamLeft = false;
            if (controlTime > 0.2f)
            {
                ModelViewerMain.GetInstance().GetCameraHandler().SetKeyframe();
                EndKeyframe();
            }
        }

        if (Input.GetMouseButtonDown(1) && !eventSystem.IsPointerOverGameObject())
        {
            StartKeyframe();
            FreeCamRight = true;
            controlTime = 0;
        }
        if (Input.GetMouseButton(1) && FreeCamRight)
        {
            controlTime += Time.deltaTime;
            transform.position += Input.GetAxis("Mouse X") * transform.right  * Time.deltaTime * moveSpeed;
            transform.position += Input.GetAxis("Mouse Y") * transform.up * Time.deltaTime * moveSpeed;
        }
        else if (FreeCamRight)
        {
            FreeCamRight = false;
            if (controlTime > 0.2f)
            {
                ModelViewerMain.GetInstance().GetCameraHandler().SetKeyframe();
                EndKeyframe();
            }
        }
        Cam.transform.localEulerAngles = settings.CamAngle * Vector3.forward;
    }
    #endregion

    #region Light
    /// <summary>
    /// Rotate Light Source
    /// </summary>
    private void OrbitLight()
    {
        if (Input.GetMouseButton(1) && !LightLock)
        {
            Light.transform.Rotate(Input.GetAxis("Mouse X") * Vector3.up, Space.Self);
            Light.transform.Rotate(Input.GetAxis("Mouse Y") * Vector3.right, Space.Self);
        }
    }

    public void SetLightColor(Color color)
    {
        Light.GetComponent<Light>().color = color;
    }

    public void SetLightIntensity(float value)
    {
        Light.GetComponent<Light>().intensity = value;
    }

    public void SetLightShadowIntensity(float value)
    {
        Light.GetComponent<Light>().shadowStrength = value;
    }

    public void SetLightShadows(int value)
    {
        Light.GetComponent<Light>().shadows = (LightShadows)value;
    }
    #endregion

    private void StartKeyframe()
    {
        var cam = ModelViewerMain.GetInstance().GetCameraHandler();
        if (cam == ModelViewerMain.GetInstance().WorkCameraOrbit)
        {
            _tempCommand = null;
            return;
        }
        _tempCommand = new CameraTransformCommand()
        {
            Container = cam,
            OldValues = cam.SerializeFrame() as KeyframeDataCamera,
            Frame = TimelineController.Instance.CurrentFrame
        };
    }

    private void EndKeyframe()
    {
        if (_tempCommand != null )
        {
            _tempCommand.NewValues = _tempCommand.Container.SerializeFrame() as KeyframeDataCamera;
            UndoRedoManager.Insert(_tempCommand);
        }
    }
}
