using System.Collections;
using UnityEngine;
using System.Linq;

public class CameraContainer: ObjectContainer
{
    public CameraOrbit Camera;
    public KeyframeDataCamera LastPosition;
    public LineRenderer LineRenderer;

    public CameraSettings Settings;

    protected override void Start()
    {
        //Set default keyframe in custom ModelViewerMain
    }

    private void Update()
    {
        if (!LineRenderer.enabled) return;

        float fov = Settings.Fov;
        float aspect = Camera.Cam.aspect;
        float nearPlane = Camera.Cam.nearClipPlane;
        float farPlane = Camera.Cam.farClipPlane;

        Vector3[] far = CalculateCameraFrustRect(fov, aspect, farPlane, transform);
        Vector3[] near = CalculateCameraFrustRect(fov, aspect, nearPlane, transform);

        var edges = new Vector3[]
        {
            far[0], far[1], far[2], far[3], far[0], near[0], near[1], near[2], near[3], near[0], near[1], far[1], far[2], near[2], near[3], far[3]
        };

        LineRenderer.positionCount = edges.Length;
        LineRenderer.SetPositions(edges);
    }

    private static Vector3[] CalculateCameraFrustRect(float fieldOfView, float aspect, float dist, Transform transform)
    {
        dist = Mathf.Clamp(dist, 0.1f, 20f);

        Vector3[] rect = new Vector3[4];
        float frustumHeight = 2.0F * dist * Mathf.Tan(fieldOfView * 0.5F * Mathf.Deg2Rad);
        rect[0] = transform.TransformPoint(new Vector3(-frustumHeight * aspect / 2, frustumHeight / 2, dist));
        rect[1] = transform.TransformPoint(new Vector3(frustumHeight * aspect / 2, frustumHeight / 2, dist));
        rect[2] = transform.TransformPoint(new Vector3(frustumHeight * aspect / 2, -frustumHeight / 2, dist));
        rect[3] = transform.TransformPoint(new Vector3(-frustumHeight * aspect / 2, -frustumHeight / 2, dist));

        return (rect);
    }

    Vector3 TransformPoint(Vector3 transforPos, Quaternion transformRotation, Vector3 transformScale, Vector3 pos)
    {
        Matrix4x4 matrix = Matrix4x4.TRS(transforPos, transformRotation, transformScale);
        return matrix.MultiplyPoint3x4(pos);
    }

    Vector3 InverseTransformPoint(Vector3 transforPos, Quaternion transformRotation, Vector3 transformScale, Vector3 pos)
    {
        Matrix4x4 matrix = Matrix4x4.TRS(transforPos, transformRotation, transformScale);
        Matrix4x4 inverse = matrix.inverse;
        return inverse.MultiplyPoint3x4(pos);
    }

    public override ObjectContainerSerializable Serialize()
    {
        var serialized = new CameraContainerSerializable(this);
        return serialized;
    }

    public override KeyframeData SerializeFrame()
    {
        return new KeyframeDataCamera(this);
    }

    public override void Deserialize(ObjectContainerSerializable serialized)
    {
        DeserializeFrames(serialized);
    }

    public override void Lerp(KeyframeData frame1, KeyframeData frame2, float amount)
    {
        var tsf = frame1 as KeyframeDataCamera;

        if (frame1 != frame2)
        {
            tsf = tsf.Lerp(frame2, amount) as KeyframeDataCamera;
        }

        var orbitLocator = ModelViewerMain.GetInstance().MainCameraOrbit;

        if (ModelViewerMain.GetInstance().GetCameraHandler() == ModelViewerMain.GetInstance().WorkCameraOrbit)
        {
            //if in work camera mode, move the camera locator only
            orbitLocator.transform.position = tsf.Root.Position;
            orbitLocator.transform.eulerAngles = tsf.Root.Rotation;
            orbitLocator.LastPosition = tsf;
        }
        else
        {
            orbitLocator.PastePose(tsf, new PoseLoadOptions(true));
        }
    }

    public override void Select()
    {
    }

    public override void Deselect()
    {
    }

    public override void PastePose(KeyframeData frame, PoseLoadOptions pasteParams = null)
    {
        var keyframe = frame as KeyframeDataCamera;
        Camera.transform.localPosition = keyframe.Root.Position;
        Camera.transform.localEulerAngles = keyframe.Root.Rotation;
        Camera.lookRotation = keyframe.Root.Rotation;
        //if (Camera.lookRotation.x > 90) Camera.lookRotation.x -= 360;
        //if (Camera.lookRotation.x < -90) Camera.lookRotation.x += 360;
        //lookRotation.x = lookRotation.x - 360;

        using (new KeyframeToggleContext(this))
        {
            Settings.DropdownCameraMode.value = keyframe.CameraMode;
            //Settings.ToggleCameraLock.isOn = keyframe.CameraLock;
            Settings.SliderFov.value = keyframe.Fov;
            Settings.SliderCamDist.value = keyframe.CamDist;
            Settings.SliderCamHeight.value = keyframe.CamHeight;
            Settings.SliderTargetHeight.value = keyframe.TargetHeigh;
            Settings.SliderCamAngle.value = keyframe.CamAngle;
        }

        Camera.UpdateImmediate();
    }

    public override void Destroy()
    {
        //Do not destroy cameras
        Frames.Clear();
        SetDefaultFrame();
    }
}