using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ChangingRoom : MonoBehaviour {

    public enum AllowedRotation { Deg90, Deg180, None };

    public List<Transform> Prefabs;
    public Vector3 BoundSize = new Vector3(4.0f,4.0f,4.0f);
    public AllowedRotation Rotation;

    public bool RandomOffset = false;

    public int ForceFirstMesh = -1;

    private Transform Spawned;

    private bool IsVisibleByCamera = false;
    private Bounds MeshBounds;
    private int SlowUpdateIndex;
    private static int TotalSlowUpdateIndex = 0;

    void TestSwitchObject() {
        Vector3 PlayerToObject = GameManager.Instance.GetPlayerPosition() - MeshBounds.center;
        bool IsOutside = false;
        IsOutside |= Mathf.Abs(PlayerToObject.x) > (MeshBounds.size.x * 0.5f + 1.0f);
        IsOutside |= Mathf.Abs(PlayerToObject.y) > (MeshBounds.size.y * 0.5f + 4.0f);
        IsOutside |= Mathf.Abs(PlayerToObject.z) > (MeshBounds.size.z * 0.5f + 1.0f);
        if (IsOutside) {
            SwitchObject(false);
        }
    }
    
    void DestroySpawned() {
        if (Spawned != null) {
            GameObject.Destroy(Spawned.gameObject);
            Spawned = null;
        }
    }

    void OnDestroy() {
        DestroySpawned();
    }

    void SwitchObject(bool IsFirstCall) {
        DestroySpawned();

        int MeshIndex = Random.Range(0, Prefabs.Count);
        if(IsFirstCall && ForceFirstMesh>=0) {
            MeshIndex = ForceFirstMesh;
        }
        Transform MeshToSpawn = Prefabs[MeshIndex];

        if (MeshToSpawn != null) {
            Transform NewMesh = Transform.Instantiate(MeshToSpawn);
            if (NewMesh) {
                NewMesh.position = transform.position;
                if (RandomOffset) {
                    float Quantity = 0.01f;
                    NewMesh.position += new Vector3(Random.value * Quantity, Random.value * Quantity, Random.value * Quantity);
                }

                Quaternion NewRot = new Quaternion();
                float Angle = 0.0f;
                switch (Rotation) {
                    case AllowedRotation.Deg90:
                        Angle = Random.Range(0, 4) * 90.0f;
                        break;
                    case AllowedRotation.Deg180:
                        Angle = Random.Range(0, 2) * 180.0f;
                        break;
                }
                NewRot.eulerAngles = new Vector3(0.0f, Angle, 0.0f);
                NewMesh.rotation = transform.rotation * NewRot;
                transform.rotation = transform.rotation * NewRot;
            }
            Spawned = NewMesh;
        }
    }

    Bounds GetBounds() {
        Vector3 RotatedSize = transform.rotation * BoundSize * 0.5f;
        Vector3 MeshCenter = transform.position + Vector3.up * RotatedSize.y;
        Bounds BasicBounds = new Bounds(MeshCenter, Vector3.one);
        BasicBounds.Encapsulate(MeshCenter + new Vector3(RotatedSize.x, RotatedSize.y, RotatedSize.z));
        BasicBounds.Encapsulate(MeshCenter + new Vector3(RotatedSize.x, RotatedSize.y, -RotatedSize.z));
        BasicBounds.Encapsulate(MeshCenter + new Vector3(RotatedSize.x, -RotatedSize.y, RotatedSize.z));
        BasicBounds.Encapsulate(MeshCenter + new Vector3(RotatedSize.x, -RotatedSize.y, -RotatedSize.z));
        BasicBounds.Encapsulate(MeshCenter + new Vector3(-RotatedSize.x, RotatedSize.y, RotatedSize.z));
        BasicBounds.Encapsulate(MeshCenter + new Vector3(-RotatedSize.x, RotatedSize.y, -RotatedSize.z));
        BasicBounds.Encapsulate(MeshCenter + new Vector3(-RotatedSize.x, -RotatedSize.y, RotatedSize.z));
        BasicBounds.Encapsulate(MeshCenter + new Vector3(-RotatedSize.x, -RotatedSize.y, -RotatedSize.z));
        return BasicBounds;
        /*
        RotatedSize.x = Mathf.Abs(RotatedSize.x);
        RotatedSize.y = Mathf.Abs(RotatedSize.y);
        RotatedSize.z = Mathf.Abs(RotatedSize.z);
        return new Bounds(transform.position + Vector3.up * RotatedSize.y * 0.5f, RotatedSize * 2.0f);*/
    }

    void Start () {
        MeshBounds = GetBounds();
        SlowUpdateIndex = TotalSlowUpdateIndex++;
        SwitchObject(true);
    }
	
	void Update () {
        if (GameManager.Instance.FullPatate) {
            int Chance = 40;
            bool CanUpdate = (SlowUpdateIndex % Chance) == (GameManager.Instance.SlowUpdateCurrent % Chance);
            if (CanUpdate) {
                bool CurrentVisible = GeometryUtility.TestPlanesAABB(GameManager.Instance.LastCameraPlanes, MeshBounds);
                if (CurrentVisible) {
                    TestSwitchObject();
                }
            }
        } else {
            bool CanUpdate = (GameManager.Instance.GetPlayerPosition() - MeshBounds.center).magnitude < 30.0f;
            if (!CanUpdate) {
                //CanUpdate = Random.value > 0.8f;
                int Chance = 100;
                CanUpdate = (SlowUpdateIndex % Chance) == (GameManager.Instance.SlowUpdateCurrent % Chance);
            }
            if (CanUpdate) {

                bool CurrentVisible = GeometryUtility.TestPlanesAABB(GameManager.Instance.LastCameraPlanes, MeshBounds);
                if (GameManager.Instance.AllowChanges) {
                    if (!CurrentVisible && IsVisibleByCamera) {
                        TestSwitchObject();
                    }
                    IsVisibleByCamera = CurrentVisible;
                }
            }
        }
    }

    void OnDrawGizmos() {
        Gizmos.color = new Color(1.0f, 1.0f, 0.0f);
        Bounds TmpBounds = GetBounds();
        Gizmos.DrawWireCube(TmpBounds.center, TmpBounds.size);
    }
}
