/**
 *  
 *  作用:镜头控制
 *  使用方法:   将该脚本放到摄像机上即可
 *  操作方法:    1、左键按下+鼠标移动 镜头旋转
 *              2、鼠标右键按下+鼠标移动 镜头平移
 *              4、鼠标滚轮滚动 镜头前进，后退
 */

using System.Collections;
using System.Collections.Generic;
using FVS;
using LitJson;
using UnityEngine;

public class FVSCamera : MonoBehaviour
{

    private static float MIN_DISTANCE = 10;
    private static float MAX_DISTANCE = 150;
    private static float MIN_ROTATE_X = 5;
    private static float MAX_ROTATE_X = 85;

    private static float MAX_DURATION = 2;
    private static float HALF_MAX_DURATION_DISTANCE = 5;

    [HideInInspector]
    public bool interactive = true;

    [LocalizedTooltip("Tooltip_RotateSpeed")]
    public float rotateSpeed = 5.0f;
    [LocalizedTooltip("Tooltip_TranslateSpeed")]
    public float translateSpeed = 5.0f;
    [LocalizedTooltip("Tooltip_ZoomSpeed")]
    public float zoomSpeed = 5.0f;

    [LocalizedTooltip("Tooltip_ZoomMax")]
    public float zoomMax = 100;

    [LocalizedTooltip("Tooltip_ZoomMin")]
    public float zoomMin = 10;

    bool interacted = false;
    void InputRotate()
    {
        // Left Button
        if (Input.GetMouseButton(0))
        {
            var lookAtTarget = GetTransformLookAtTarget(transform);

            var mouseMovement = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));

            mouseMovement *= rotateSpeed;

            transform.RotateAround(lookAtTarget, Vector3.up, mouseMovement.x);

            // rotate around camera's local x axis;
            Vector3 left = -transform.right;
            left.y = 0;

            Vector3 rotationAngles = transform.rotation.eulerAngles;

            float finalRotateX = rotationAngles.x - mouseMovement.y;

            // 限制镜头X轴旋转在 5~85度之间.
            if (MIN_ROTATE_X < finalRotateX && finalRotateX < MAX_ROTATE_X)
            {
                transform.RotateAround(lookAtTarget, left.normalized, mouseMovement.y);
            }

            interacted = true;
        }
    }

    void InputTranslate()
    {
        // Right Button
        if (Input.GetMouseButton(1))
        {
            Vector3 direction = new Vector3();
            var x = -Input.GetAxis("Mouse X");
            var y = -Input.GetAxis("Mouse Y");

            // keep the camera parallel to the ground

            Vector3 right = transform.right;
            right.y = 0;
            direction += right.normalized * x;

            Vector3 forward = transform.forward;
            forward.y = 0;
            direction += forward.normalized * y;

            direction *= translateSpeed;


            transform.position += direction;

            interacted = true;
        }
    }

    void InputZoom()
    {
        if (Input.mouseScrollDelta.y == 0)
        {
            return;
        }

        if (FVSClickable.zoomObserverEnabled && FVSClickable.currentClickedName != null)
        {
            HandleZoomChanged();
        }

        var lookAtTarget = GetTransformLookAtTarget(transform);
        var distance = Vector3.Distance(lookAtTarget, transform.position);

        Vector3 direction = new Vector3();
        if (Input.mouseScrollDelta.y > 0 && distance > zoomMin)
        {
            direction += Vector3.forward;
        }
        else if (Input.mouseScrollDelta.y < 0 && distance < zoomMax)
        {
            direction += Vector3.back;
        }

        direction *= zoomSpeed;

        Vector3 rotatedTranslation = transform.rotation * direction;
        transform.position += rotatedTranslation;

        interacted = true;
    }

    void ListenOnMouseEvent()
    {
        InputRotate();
        InputTranslate();
        InputZoom();

        if (interacted && Input.GetMouseButtonUp(0) || Input.GetMouseButtonUp(1) || Input.mouseScrollDelta.y != 0)
        {
            interacted = false;
            //MessageCenter.instance.DispatchEvent("cameramanipulated", GetCameraState());
        }
    }

    void Update()
    {
        if (interactive)
        {
            ListenOnMouseEvent();
        }
    }

    public static Vector3 GetTransformLookAtTarget(Transform trans)
    {
        return GetTransformLookAtTarget(trans.position, trans.rotation);
    }

    public static Vector3 GetTransformLookAtTarget(Vector3 position, Quaternion rotation)
    {
        Vector3 direction = Vector3.Normalize(rotation * Vector3.forward);

        Vector3 camPos = position;

        float scale = camPos.y / direction.y;
        float x = camPos.x - direction.x * scale;
        float z = camPos.z - direction.z * scale;

        return new Vector3(x, 0, z);
    }

    private void HandleZoomChanged() {
        FVSClickable[] clickableObjects = FindObjectsOfType<FVSClickable>();
        foreach (FVSClickable clickableObject in clickableObjects)
        {
            if (clickableObject.IsSelected())
            {
                Vector3 worldPosition = clickableObject.transform.position;
                Vector3 screenPosition = Camera.main.WorldToScreenPoint(worldPosition);
                JsonWriter jw = new JsonWriter();
                jw.WriteObjectStart();
                jw.WritePropertyName("clickableName");
                jw.Write(FVSClickable.currentClickedName);
                jw.WritePropertyName("screenX");
                jw.Write(screenPosition.x);
                jw.WritePropertyName("screenY");
                jw.Write(screenPosition.y);
                jw.WriteObjectEnd();
                FVSUnityReact.Instance.SendMessageToReact(MessageType.UpdateClickableScreenPos, jw.ToString());
            }
        }
    }
}


