﻿using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Animations;
#if VRC_SDK_VRCSDK3
  using VRCAvatarDescriptorType = VRC.SDK3.Avatars.Components.VRCAvatarDescriptor; 
#elif VRC_SDK_VRCSDK2
  using VRCAvatarDescriptorType = VRC.SDKBase.VRC_AvatarDescriptor; 
#endif

[ExecuteInEditMode]
public class JaceCamSetup : MonoBehaviour
{
  public VRCAvatarDescriptorType AvatarDescriptor;
  // Head object in armature for face camera to track
  public Transform HeadBone;
  // Delete this component after setup, so avatar can be built
  public bool DeleteAfterSetup = true;

  // Start is called before the first frame update
  void OnEnable() {
    if (!AvatarDescriptor) {
      AvatarDescriptor = gameObject.GetComponentInParent<VRCAvatarDescriptorType>();
    }
    if (!HeadBone) {
      HeadBone = FindChild(transform.root, "Head");
    }

    // Disable culling mask when added, so user can position camera
    var cam = gameObject.GetComponentInChildren<Camera>();
    cam.cullingMask = -1;
    // Disable constraint temporarily
    var constraint = gameObject.GetComponent<ParentConstraint>();
    constraint.constraintActive = false;
  }

  void Reset() {
    AvatarDescriptor = gameObject.GetComponentInParent<VRCAvatarDescriptorType>();
    HeadBone = FindChild(transform.root, "Head");
    // Disable culling mask when added, so user can position camera
    var cam = gameObject.GetComponentInChildren<Camera>();
    cam.cullingMask = -1;
    // Disable constraint temporarily
    var constraint = gameObject.GetComponent<ParentConstraint>();
    constraint.constraintActive = false;
  }

  public void Setup() {
    // Set camera culling to MirrorReflection layer (18)
    var cam = gameObject.GetComponentInChildren<Camera>();
    cam.cullingMask = 1 << 18;

    // Add parent constraint to head
    var constraint = gameObject.GetComponent<ParentConstraint>();
    constraint.SetSources(new List<ConstraintSource> { new ConstraintSource { sourceTransform = HeadBone, weight = 1 } });
    // constraint.SetTranslationOffset(0, Quaternion.Inverse(transform.rotation) * (transform.position - HeadBone.position));
    constraint.SetTranslationOffset(0, HeadBone.InverseTransformPoint(transform.position));
    constraint.SetRotationOffset(0, (Quaternion.Inverse(HeadBone.rotation) * transform.rotation).eulerAngles); 
    constraint.constraintActive = true;

    // Move HUD to VR view position
    var mesh = gameObject.GetComponentInChildren<MeshRenderer>();
    mesh.transform.position = AvatarDescriptor.transform.position + AvatarDescriptor.ViewPosition;

    if (DeleteAfterSetup) {
      DestroyImmediate(this);
    }
  }

  static Transform FindChild(Transform parent, string name) {
    var queue = new Queue<Transform>();
    queue.Enqueue(parent);
    while (queue.Count > 0) {
      var c = queue.Dequeue();
      if (c.name == name)
        return c;
      foreach (Transform t in c)
        queue.Enqueue(t);
    }
    return null;
  }
}
