/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * Licensed under the Oculus SDK License Agreement (the "License");
 * you may not use the Oculus SDK except in compliance with the License,
 * which is provided at the time of installation or download, or which
 * otherwise accompanies this software in either electronic or hard copy form.
 *
 * You may obtain a copy of the License at
 *
 * https://developer.oculus.com/licenses/oculussdk/
 *
 * Unless required by applicable law or agreed to in writing, the Oculus SDK
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

using UnityEngine;

/// <summary>
/// A <see cref="OVRSceneAnchor"/> that has a 3D bounds associated with it.
/// </summary>
[DisallowMultipleComponent]
[RequireComponent(typeof(OVRSceneAnchor))]
public class OVRSceneVolume : MonoBehaviour, IOVRSceneComponent
{
    /// <summary>
    /// The width (in the local X-direction), in meters.
    /// </summary>
    public float Width { get; private set; }

    /// <summary>
    /// The height (in the local Y-direction), in meters.
    /// </summary>
    public float Height { get; private set; }

    /// <summary>
    /// The depth (in the local Z-direction), in meters.
    /// </summary>
    public float Depth { get; private set; }

    /// <summary>
    /// The dimensions of the volume.
    /// </summary>
    /// <remarks>
    /// This property corresponds to a Vector whose components are
    /// (<see cref="Width"/>, <see cref="Height"/>, <see cref="Depth"/>).
    /// </remarks>
    public Vector3 Dimensions => new Vector3(Width, Height, Depth);

    /// <summary>
    /// Whether the child transforms will be scaled according to the dimensions of this volume.
    /// </summary>
    /// <remarks>If set to True, all the child transforms will be scaled to the dimensions of this volume immediately.
    /// And, if it's set to False, dimensions of this volume will no longer affect the child transforms, and child
    /// transforms will retain their current scale.</remarks>
    public bool ScaleChildren
    {
        get => _scaleChildren;
        set
        {
            _scaleChildren = value;
            if (_scaleChildren && _sceneAnchor.Space.Valid)
            {
                SetChildScale(transform, Dimensions);
            }
        }
    }

    [Tooltip("When enabled, scales the child transforms according to the dimensions of this volume")]
    [SerializeField]
    private bool _scaleChildren = true;

    private OVRSceneAnchor _sceneAnchor;

    private void Awake()
    {
        _sceneAnchor = GetComponent<OVRSceneAnchor>();
        if (_sceneAnchor.Space.Valid)
        {
            ((IOVRSceneComponent)this).Initialize();
        }
    }

    void IOVRSceneComponent.Initialize()
    {
        UpdateTransform();
    }

    private static void SetChildScale(Transform parentTransform, Vector3 dimensions)
    {
        for (var i = 0; i < parentTransform.childCount; i++)
        {
            parentTransform.GetChild(i).localScale = dimensions;
        }
    }

    internal void UpdateTransform()
    {
        if (OVRPlugin.GetSpaceBoundingBox3D(_sceneAnchor.Space, out var bounds))
        {
            Width = bounds.Size.w;
            Height = bounds.Size.h;
            Depth = bounds.Size.d;

            var dimensions = Dimensions;
            OVRSceneManager.Development.Log(nameof(OVRSceneVolume),
                $"[{_sceneAnchor.Uuid}] Volume has dimensions {dimensions}.");

            if (ScaleChildren)
            {
                SetChildScale(transform, dimensions);
            }
        }
        else
        {
            OVRSceneManager.Development.LogError(nameof(OVRSceneVolume),
                $"[{_sceneAnchor.Space}] Failed to retrieve volume's dimensions.");
        }
    }
}
