// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
// for ex. property getter/setter access. To get optimal decompilation results, please manually add the missing references to the list of loaded assemblies.
// EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// Eden.AutoMorpher.BodyPoseMatch_CommonUtil
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class BodyPoseMatch_CommonUtil
{
    public Transform GetBoneFromBoneMap(Dictionary<HumanBodyBones, HashSet<Transform>> boneMap, HumanBodyBones bone)
    {
        if (boneMap == null || !boneMap.TryGetValue(bone, out var value) || value == null)
        {
            return null;
        }
        return value.FirstOrDefault();
    }

    public Vector3 GetProfilePcaCenterWorld(Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap, BoneSpatialData boneSpatialData, Vector3 comprehensiveScale, string errorContext = "")
    {
        if (clothBoneMap == null)
        {
            throw new AutoMorpherException("Cloth Bone Map is Missing", "[BodyPoseMatch_CommonUtil] GetProfilePcaCenterWorld\n - clothBoneMap is null (context=" + errorContext + ")");
        }
        if (boneSpatialData == null || boneSpatialData.pcaData == null)
        {
            throw new AutoMorpherException("Profile Bone Spatial Data is Missing", "[BodyPoseMatch_CommonUtil] GetProfilePcaCenterWorld\n - boneSpatialData or boneSpatialData.pcaData is null (context=" + errorContext + ")");
        }
        Transform boneFromBoneMap = this.GetBoneFromBoneMap(clothBoneMap, boneSpatialData.refBone);
        if (boneFromBoneMap == null)
        {
            throw new AutoMorpherException("Profile Ref Bone Transform is Missing", "[BodyPoseMatch_CommonUtil] GetProfilePcaCenterWorld" + $"\n - refBone transform is null (refBone={boneSpatialData.refBone}, context={errorContext})");
        }
        if (this.GetBoneFromBoneMap(clothBoneMap, HumanBodyBones.Hips) == null)
        {
            throw new AutoMorpherException("Hip Transform is Missing", "[BodyPoseMatch_CommonUtil] GetProfilePcaCenterWorld\n - hip transform is null (context=" + errorContext + ")");
        }
        Vector3 pcaCenter = boneSpatialData.pcaData.pcaCenter;
        Vector3 position = new Vector3(pcaCenter.x / comprehensiveScale.x, pcaCenter.y / comprehensiveScale.y, pcaCenter.z / comprehensiveScale.z);
        return boneFromBoneMap.TransformPoint(position);
    }

    public Vector3 GetProfileVolumeMinWorld(Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap, BoneSpatialData spatialData, int axis, Vector3 comprehensiveScale)
    {
        return this.GetProfileVolumeWorld(clothBoneMap, spatialData, axis, comprehensiveScale, isMin: true);
    }

    public Vector3 GetProfileVolumeMaxWorld(Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap, BoneSpatialData spatialData, int axis, Vector3 comprehensiveScale)
    {
        return this.GetProfileVolumeWorld(clothBoneMap, spatialData, axis, comprehensiveScale, isMin: false);
    }

    public Vector3 GetProfileVolumeWorld(Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap, BoneSpatialData spatialData, int axisIndex, Vector3 comprehensiveScale, bool isMin)
    {
        if (clothBoneMap == null)
        {
            throw new AutoMorpherException("Cloth Bone Map is Missing", "[BodyPoseMatch_CommonUtil] GetProfileVolumeWorld\n - clothBoneMap is null");
        }
        if (spatialData == null || spatialData.volumeData == null)
        {
            throw new AutoMorpherException("Profile Volume Data is Missing", "[BodyPoseMatch_CommonUtil] GetProfileVolumeWorld\n - spatialData or spatialData.volumeData is null");
        }
        Transform boneFromBoneMap = this.GetBoneFromBoneMap(clothBoneMap, spatialData.refBone);
        if (boneFromBoneMap == null)
        {
            throw new AutoMorpherException("Profile Ref Bone Transform is Missing", "[BodyPoseMatch_CommonUtil] GetProfileVolumeWorld" + $"\n - refBone transform is null (refBone={spatialData.refBone})");
        }
        Vector3 vector = axisIndex switch
        {
            0 => isMin ? spatialData.volumeData.fMinLocalPos : spatialData.volumeData.fMaxLocalPos,
            1 => isMin ? spatialData.volumeData.rMinLocalPos : spatialData.volumeData.rMaxLocalPos,
            2 => isMin ? spatialData.volumeData.uMinLocalPos : spatialData.volumeData.uMaxLocalPos,
            _ => throw new AutoMorpherException("Unsupported Volume Axis Index", "[BodyPoseMatch_CommonUtil] GetProfileVolumeWorld" + $"\n - axisIndex must be 0(Forward), 1(Right), 2(Up) (axisIndex={axisIndex})"),
        };
        Vector3 position = new Vector3(vector.x / comprehensiveScale.x, vector.y / comprehensiveScale.y, vector.z / comprehensiveScale.z);
        return boneFromBoneMap.TransformPoint(position);
    }

    public List<Vector3> CollectWeightedVerticesWorld(IReadOnlyList<BakedBodyMesh> bakedBodyMeshes, HashSet<Transform> targetBoneSet, float weightThreshold = 0.15f, int sampleStep = 1)
    {
        List<Vector3> list = new List<Vector3>();
        if (bakedBodyMeshes == null || targetBoneSet == null || targetBoneSet.Count == 0)
        {
            return list;
        }
        foreach (BakedBodyMesh bakedBodyMesh in bakedBodyMeshes)
        {
            if (bakedBodyMesh == null || bakedBodyMesh.smr == null)
            {
                continue;
            }
            Mesh sharedMesh = bakedBodyMesh.smr.sharedMesh;
            if (sharedMesh == null)
            {
                continue;
            }
            BoneWeight[] boneWeights = sharedMesh.boneWeights;
            Transform[] bones = bakedBodyMesh.smr.bones;
            if (boneWeights == null || boneWeights.Length == 0 || bones == null || bones.Length == 0)
            {
                continue;
            }
            Vector3[] worldVerticesWithBakedMesh = new WorldVertexUtil().GetWorldVerticesWithBakedMesh(bakedBodyMesh.smr, bakedBodyMesh.bakedMesh);
            if (worldVerticesWithBakedMesh == null)
            {
                continue;
            }
            int num = Mathf.Min(worldVerticesWithBakedMesh.Length, boneWeights.Length);
            for (int i = 0; i < num; i += sampleStep)
            {
                BoneWeight boneWeight = boneWeights[i];
                float wSum = 0f;
                Acc(boneWeight.boneIndex0, boneWeight.weight0);
                Acc(boneWeight.boneIndex1, boneWeight.weight1);
                Acc(boneWeight.boneIndex2, boneWeight.weight2);
                Acc(boneWeight.boneIndex3, boneWeight.weight3);
                if (!(wSum < weightThreshold))
                {
                    list.Add(worldVerticesWithBakedMesh[i]);
                }
                void Acc(int index, float w)
                {
                    if (index >= 0 && index < bones.Length && !(w <= 0f))
                    {
                        Transform transform = bones[index];
                        if (transform != null && targetBoneSet.Contains(transform))
                        {
                            wSum += w;
                        }
                    }
                }
            }
        }
        return list;
    }

    public List<Vector3> CollectHumanoidVerticesWorld(IReadOnlyList<HumanBodyBones> targetHumanBones, IReadOnlyList<BakedBodyMesh> bakedBodyMeshes, Dictionary<HumanBodyBones, HashSet<Transform>> boneMap, float weightThreshold = 0.15f, int sampleStep = 1)
    {
        List<Vector3> result = new List<Vector3>();
        if (bakedBodyMeshes == null || boneMap == null || boneMap.Count == 0 || targetHumanBones == null)
        {
            throw new AutoMorpherException("Invalid Arguments for CollectHumanoidVerticesWorld", "[BodyPoseMatchCommonUtil] CollectHumanoidVerticesWorld\n - bakedBodyMeshes is null OR boneMap is null/empty OR targetHumanBones is null");
        }
        HashSet<Transform> hashSet = new HashSet<Transform>();
        foreach (HumanBodyBones targetHumanBone in targetHumanBones)
        {
            if (!boneMap.TryGetValue(targetHumanBone, out var value) || value == null)
            {
                continue;
            }
            foreach (Transform item in value)
            {
                if (item != null)
                {
                    hashSet.Add(item);
                }
            }
        }
        if (hashSet.Count == 0)
        {
            Debug.Log("[AvatarBodyMatchUtil] CollectBodyPartVerticesWorld: targetBoneSet is empty.");
            return result;
        }
        return this.CollectWeightedVerticesWorld(bakedBodyMeshes, hashSet, weightThreshold, sampleStep);
    }

    public void BoneLengthAdjust(Transform proxyParent, Transform proxyChild, Transform targetParent, Transform targetChild, HashSet<Transform> proxyParentSet, bool autoDetectAxis = true, int forceAxisIndex = 1)
    {
        if (proxyParent == null || proxyChild == null || targetParent == null || targetChild == null)
        {
            Debug.LogWarning("[AvatarBodyMatchUtil] MatchBoneSegmentLength: bone null");
            return;
        }
        float num = Vector3.Distance(proxyParent.position, proxyChild.position);
        float num2 = Vector3.Distance(targetParent.position, targetChild.position);
        if (num < 1E-06f || num2 < 1E-06f)
        {
            Debug.LogWarning($"[AvatarBodyMatchUtil] MatchBoneSegmentLength: too small length. proxy={num}, target={num2}");
            return;
        }
        float num3 = num2 / num;
        int num7;
        if (autoDetectAxis)
        {
            Vector3 direction = proxyChild.position - proxyParent.position;
            Vector3 vector = proxyParent.InverseTransformDirection(direction);
            float num4 = Mathf.Abs(vector.x);
            float num5 = Mathf.Abs(vector.y);
            float num6 = Mathf.Abs(vector.z);
            num7 = ((num5 >= num4 && num5 >= num6) ? 1 : ((!(num4 >= num6)) ? 2 : 0));
        }
        else
        {
            num7 = Mathf.Clamp(forceAxisIndex, 0, 2);
        }
        Vector3 localScale = proxyParent.localScale;
        switch (num7)
        {
            case 0:
                localScale.x *= num3;
                break;
            case 1:
                localScale.y *= num3;
                break;
            case 2:
                localScale.z *= num3;
                break;
        }
        foreach (Transform item in proxyParentSet)
        {
            item.localScale = localScale;
        }
    }

    public Transform CreateTempMarker(string markerObjectName, Transform parentTransform, IReadOnlyList<Transform> childTransforms, Vector3 markerWorldPosition, Quaternion markerWorldRotation, Vector3 markerLocalScale, out TempBoneMarker tempBoneMarker)
    {
        if (parentTransform == null)
        {
            throw new AutoMorpherException("Marker Parent Transform is Missing", "[BodyPoseMatch_CommonUtil] CreateTempMarker\n - parentTransform is null");
        }
        if (childTransforms == null || childTransforms.Count == 0)
        {
            throw new AutoMorpherException("Child Transforms are Missing", "[BodyPoseMatch_CommonUtil] CreateTempMarker\n - childTransforms is null or empty");
        }
        Transform transform = new GameObject(string.IsNullOrEmpty(markerObjectName) ? "scaleSupportBone" : markerObjectName).transform;
        transform.SetParent(parentTransform, worldPositionStays: true);
        transform.position = markerWorldPosition;
        transform.rotation = markerWorldRotation;
        transform.localScale = markerLocalScale;
        tempBoneMarker = transform.gameObject.AddComponent<TempBoneMarker>();
        tempBoneMarker.originalParent = parentTransform;
        tempBoneMarker.additionalInfo = "";
        tempBoneMarker.wrappedChildNames = new List<string>();
        for (int i = 0; i < childTransforms.Count; i++)
        {
            Transform transform2 = childTransforms[i];
            if (!(transform2 == null))
            {
                tempBoneMarker.wrappedChildNames.Add(transform2.name);
                transform2.SetParent(transform, worldPositionStays: true);
            }
        }
        return transform;
    }
}
