using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Events;
using SimpleJSON;
namespace Disa
{
    // Manages trigger zones for orifices (e.g., Mouth, Vagina, Anus) on a selected Atom (character) in a Unity-based scene.
    // Tracks penetration and proximity events, manages penis colliders for male atoms, and handles UI for configuration.
    public class OrificeTriggerManager : MVRScript
    {
        public static OrificeTriggerManager singleton;
        private Atom selectedAtom;
        private List<object> uiElements;
        private List<JSONStorableFloat> sliderStorables;
        private List<JSONStorableBool> toggleStorables;
        private List<JSONStorableString> textFieldStorables;
        private List<UIDynamicButton> buttonElements;
        private string selectedOrifice;
        private Dictionary<string, Orifice> orifices;
        private Dictionary<string, ProximityHandler> proximityHandlers;
        private Dictionary<string, OrificeTriggerHandler> triggerHandlers;
        private bool debugVisible = true;
        private bool penisCollidersVisible = false;
        private Dictionary<Atom, List<GameObject>> penisViz = new Dictionary<Atom, List<GameObject>>();
        private JSONStorableString mouthStatus;
        private JSONStorableString vaginaStatus;
        private JSONStorableString anusStatus;
        private JSONStorableString mouthProxStatus;
        private JSONStorableString vaginaProxStatus;
        private JSONStorableString anusProxStatus;
        private List<Atom> maleAtoms;
        public Dictionary<Atom, Penis> penises;
        public Dictionary<string, Orifice> Orifices
        {
            get { return orifices; }
        }
        // Initializes the manager, sets up status tracking, finds male atoms, and creates the UI.
        public override void Init()
        {
            singleton = this;
            SuperController.LogMessage("OrificeTriggerManager: Initialization started");
            uiElements = new List<object>();
            sliderStorables = new List<JSONStorableFloat>();
            toggleStorables = new List<JSONStorableBool>();
            textFieldStorables = new List<JSONStorableString>();
            buttonElements = new List<UIDynamicButton>();
            orifices = new Dictionary<string, Orifice>();
            proximityHandlers = new Dictionary<string, ProximityHandler>();
            triggerHandlers = new Dictionary<string, OrificeTriggerHandler>();
            selectedOrifice = "Mouth";
            maleAtoms = new List<Atom>();
            penises = new Dictionary<Atom, Penis>();
            // Initialize status strings for tracking penetration and proximity
            mouthStatus = new JSONStorableString("Mouth Status", "Penis in mouth: No");
            vaginaStatus = new JSONStorableString("Vagina Status", "Penis in vagina: No");
            anusStatus = new JSONStorableString("Anus Status", "Penis in anus: No");
            mouthProxStatus = new JSONStorableString("Mouth Proximity", "Penis near mouth: No");
            vaginaProxStatus = new JSONStorableString("Vagina Proximity", "Penis near vagina: No");
            anusProxStatus = new JSONStorableString("Anus Proximity", "Penis near anus: No");
            selectedAtom = containingAtom;
            if (selectedAtom == null || selectedAtom.type != "Person")
            {
                SuperController.LogError("OrificeTriggerManager: This script must be added to a Person-type atom.");
                return;
            }
            SuperController.LogMessage("OrificeTriggerManager: Atom automatically selected: " + selectedAtom.uid);
            SelectAtom(selectedAtom.uid);
            FindMaleAtoms();
            CreateUI();
            SuperController.LogMessage("OrificeTriggerManager: Initialization completed");
        }
        // Finds male atoms in the scene and initializes their penis colliders.
        private void FindMaleAtoms()
        {
            maleAtoms.Clear();
            penises.Clear();
            penisViz.Clear();
            
            List<Atom> allAtoms = SuperController.singleton.GetAtoms();
            for (int i = 0; i < allAtoms.Count; i++)
            {
                Atom atom = allAtoms;
                if (atom.type == "Person" && atom != selectedAtom)
                {
                    if (HasPenis(atom))
                    {
                        maleAtoms.Add(atom);
                        penises[atom] = new Penis(atom);
                        SuperController.LogMessage("OrificeTriggerManager: Found male atom: " + atom.uid);
                    }
                }
            }
        }
        // Checks if an atom has penis-related components or colliders.
        private bool HasPenis(Atom atom)
        {
            if (atom.GetStorableByID("penisTipControl") != null) return true;
            if (atom.GetStorableByID("penisMidControl") != null) return true;
            if (atom.GetStorableByID("penisBaseControl") != null) return true;
            
            Collider[] colliders = atom.GetComponentsInChildren<Collider>();
            foreach (var col in colliders)
            {
                string colNameLower = col.name.ToLower();
                if ((colNameLower.Contains("autocollidergen") || colNameLower.Contains("autogen")) &&
                    (colNameLower.Contains("hard") || colNameLower.Contains("soft")))
                {
                    Rigidbody[] rbs = col.GetComponentsInParent<Rigidbody>();
                    foreach (var rb in rbs)
                    {
                        if (rb.name.ToLower().Contains("penis"))
                            return true;
                    }
                }
            }
            return false;
        }
        // Selects an atom and sets up its orifices and triggers.
        public void SelectAtom(string atomUid)
        {
            selectedAtom = SuperController.singleton.GetAtomByUid(atomUid);
            if (selectedAtom == null)
            {
                SuperController.LogError("OrificeTriggerManager: Atom " + atomUid + " not found.");
                return;
            }
            SuperController.LogMessage("OrificeTriggerManager: Atom selected: " + atomUid);
            orifices.Clear();
            proximityHandlers.Clear();
            triggerHandlers.Clear();
            try
            {
                string[] orificeNames = new string[] { "Mouth", "Vagina", "Anus" };
                for (int i = 0; i < orificeNames.Length; i++)
                {
                    string orificeName = orificeNames;
                    Orifice orifice = selectedAtom.gameObject.AddComponent<Orifice>();
                    if (orifice != null)
                    {
                        orifice.Init(orificeName, selectedAtom);
                        if (orifice.rb != null)
                        {
                            orifices[orificeName] = orifice;
                            SetupTriggers(orifice, orificeName);
                            SuperController.LogMessage("OrificeTriggerManager: Created " + orificeName);
                        }
                        else
                        {
                            SuperController.LogError("OrificeTriggerManager: Failed to initialize " + orificeName + " due to missing Rigidbody");
                            UnityEngine.Object.Destroy(orifice);
                        }
                    }
                    else
                    {
                        SuperController.LogError("OrificeTriggerManager: Failed to create Orifice component for " + orificeName);
                    }
                }
            }
            catch (Exception e)
            {
                SuperController.LogError("OrificeTriggerManager: Error creating orifices: " + e.Message);
            }
            UpdateAllStatuses();
            CreateUI();
        }
        // Sets up trigger and proximity colliders for an orifice, including their position, scale, and visual debugging.
        private void SetupTriggers(Orifice orifice, string name)
        {
            if (orifice == null || orifice.rb == null)
            {
                SuperController.LogError("OrificeTriggerManager: Orifice or Rigidbody null for " + name);
                return;
            }
            try
            {
                // Create entry trigger
                GameObject triggerGO = GameObject.CreatePrimitive(PrimitiveType.Capsule);
                triggerGO.name = "BL_" + name + "_EnterTrigger";
                CapsuleCollider enterTriggerCollider = triggerGO.GetComponent<CapsuleCollider>();
                enterTriggerCollider.isTrigger = true;
                triggerGO.transform.SetParent(orifice.rb.transform, false);
                if (name == "Mouth")
                {
                    triggerGO.transform.localRotation = Quaternion.Euler(90, 0, 0);
                }
                else if (name == "Anus")
                {
                    triggerGO.transform.localRotation = Quaternion.Euler(25, 0, 0);
                }
                else
                {
                    triggerGO.transform.localRotation = Quaternion.identity;
                }
                triggerGO.transform.localScale = new Vector3(orifice.triggerScale.val, orifice.triggerScale.val, orifice.triggerScale.val);
                triggerGO.transform.localPosition = new Vector3(0f, orifice.triggerOffsetUp.val + orifice.defaultUp, orifice.triggerOffsetForward.val + orifice.defaultForward);
                Renderer renderer = triggerGO.GetComponent<Renderer>();
                if (renderer != null)
                {
                    renderer.material = new Material(Shader.Find("Standard"));
                    renderer.material.color = new Color(0f, 0f, 1f, 0.5f);
                    renderer.enabled = debugVisible;
                }
                // Create proximity trigger
                GameObject proximityGO = GameObject.CreatePrimitive(PrimitiveType.Capsule);
                proximityGO.name = "BL_" + name + "_ProximityTrigger";
                CapsuleCollider proximityTrigger = proximityGO.GetComponent<CapsuleCollider>();
                proximityTrigger.isTrigger = true;
                proximityGO.transform.SetParent(orifice.rb.transform, false);
                if (name == "Mouth")
                {
                    proximityGO.transform.localRotation = Quaternion.Euler(90, 0, 0);
                }
                else if (name == "Anus")
                {
                    proximityGO.transform.localRotation = Quaternion.Euler(25, 0, 0);
                }
                else
                {
                    proximityGO.transform.localRotation = Quaternion.identity;
                }
                proximityGO.transform.localScale = new Vector3(orifice.proximityScale.val, orifice.proximityScale.val, orifice.proximityScale.val);
                proximityGO.transform.localPosition = new Vector3(0f, orifice.triggerOffsetUp.val + orifice.defaultUp, orifice.triggerOffsetForward.val + orifice.defaultForward);
                Renderer proxRenderer = proximityGO.GetComponent<Renderer>();
                if (proxRenderer != null)
                {
                    proxRenderer.material = new Material(Shader.Find("Standard"));
                    proxRenderer.material.SetFloat("_Mode", 2);
                    proxRenderer.material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
                    proxRenderer.material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                    proxRenderer.material.SetInt("_ZWrite", 0);
                    proxRenderer.material.DisableKeyword("_ALPHATEST_ON");
                    proxRenderer.material.EnableKeyword("_ALPHABLEND_ON");
                    proxRenderer.material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                    proxRenderer.material.color = new Color(1f, 1f, 0f, 0.3f);
                    proxRenderer.enabled = debugVisible && orifice.showProximity.val;
                }
                OrificeTriggerHandler triggerHandler = triggerGO.AddComponent<OrificeTriggerHandler>();
                if (triggerHandler != null)
                {
                    triggerHandler.orifice = orifice;
                    triggerHandler.isActive = true;
                    triggerHandlers[name] = triggerHandler;
                }
                ProximityHandler proximityHandler = proximityGO.AddComponent<ProximityHandler>();
                if (proximityHandler != null)
                {
                    proximityHandler.orifice = orifice;
                    proximityHandler.on = true;
                    proximityHandlers[name] = proximityHandler;
                }
                orifice.enterTriggerCollider = enterTriggerCollider;
                orifice.proximityTrigger = proximityTrigger;
                orifice.showProximity.setCallbackFunction = (bool val) =>
                {
                    if (proxRenderer != null) proxRenderer.enabled = debugVisible && val;
                };
                orifice.triggerOffsetUp.setCallbackFunction = (float val) =>
                {
                    if (triggerGO != null) triggerGO.transform.localPosition = new Vector3(0f, val + orifice.defaultUp, orifice.triggerOffsetForward.val + orifice.defaultForward);
                    if (proximityGO != null) proximityGO.transform.localPosition = new Vector3(0f, val + orifice.defaultUp, orifice.triggerOffsetForward.val + orifice.defaultForward);
                };
                orifice.triggerOffsetForward.setCallbackFunction = (float val) =>
                {
                    if (triggerGO != null) triggerGO.transform.localPosition = new Vector3(0f, orifice.triggerOffsetUp.val + orifice.defaultUp, val + orifice.defaultForward);
                    if (proximityGO != null) proximityGO.transform.localPosition = new Vector3(0f, orifice.triggerOffsetUp.val + orifice.defaultUp, val + orifice.defaultForward);
                };
                orifice.triggerScale.setCallbackFunction = (float val) =>
                {
                    if (triggerGO != null) triggerGO.transform.localScale = new Vector3(val, val, val);
                };
                orifice.proximityScale.setCallbackFunction = (float val) =>
                {
                    if (proximityGO != null) proximityGO.transform.localScale = new Vector3(val, val, val);
                };
            }
            catch (Exception e)
            {
                SuperController.LogError("OrificeTriggerManager: Error in SetupTriggers for " + name + ": " + e.Message);
            }
        }
        // Creates the UI for configuring orifices and toggling debug/penis collider visibility.
        private void CreateUI()
        {
            ClearUI();
            try
            {
                SetupButton("Mouth Settings", false, delegate { SelectOrifice("Mouth"); });
                SetupButton("Vagina Settings", true, delegate { SelectOrifice("Vagina"); });
                SetupButton("Anus Settings", false, delegate { SelectOrifice("Anus"); });
                SetupButton("Debug", true, ToggleDebugVisibility);
                SetupButton("Penis Colliders", true, TogglePenisColliders);
                AddStatusUIElements();
                SelectOrifice(selectedOrifice);
            }
            catch (Exception e)
            {
                SuperController.LogError("OrificeTriggerManager: Error creating UI: " + e.Message);
            }
        }
        // Toggles visibility of trigger and proximity colliders for debugging.
        private void ToggleDebugVisibility()
        {
            debugVisible = !debugVisible;
            foreach (var pair in orifices)
            {
                Orifice orifice = pair.Value;
                if (orifice.enterTriggerCollider != null)
                {
                    Renderer renderer = orifice.enterTriggerCollider.gameObject.GetComponent<Renderer>();
                    if (renderer != null) renderer.enabled = debugVisible;
                }
                if (orifice.proximityTrigger != null)
                {
                    Renderer proxRenderer = orifice.proximityTrigger.gameObject.GetComponent<Renderer>();
                    if (proxRenderer != null) proxRenderer.enabled = debugVisible && orifice.showProximity.val;
                }
            }
            SuperController.LogMessage("OrificeTriggerManager: Trigger visibility " + (debugVisible ? "enabled" : "disabled"));
        }
        // Toggles visibility of penis colliders for debugging.
        private void TogglePenisColliders()
        {
            penisCollidersVisible = !penisCollidersVisible;
            
            if (penisCollidersVisible)
            {
                FindMaleAtoms();
                for (int i = 0; i < maleAtoms.Count; i++)
                {
                    CreatePenisColliderViz(maleAtoms);
                }
            }
            else
            {
                HideAllPenisViz();
            }
            
            SuperController.LogMessage("OrificeTriggerManager: Penis collider visibility " + (penisCollidersVisible ? "enabled" : "disabled"));
        }
        // Creates visual representations for penis colliders on a male atom.
        private void CreatePenisColliderViz(Atom male)
        {
            if (penisViz.ContainsKey(male))
            {
                List<GameObject> list = penisViz[male];
                for (int i = 0; i < list.Count; i++)
                {
                    GameObject v = list;
                    if (v != null)
                    {
                        v.SetActive(true);
                        Renderer r = v.GetComponent<Renderer>();
                        if (r != null) r.enabled = true;
                    }
                }
                return;
            }
            List<GameObject> vizList = new List<GameObject>();
            Penis penis = penises.ContainsKey(male) ? penises[male] : null;
            
            if (penis == null)
            {
                SuperController.LogMessage($"CreatePenisColliderViz: Penis object not found for {male.uid}");
                return;
            }
            
            // Create transparent material once
            Material transparentMat = new Material(Shader.Find("Standard"));
            transparentMat.SetFloat("_Mode", 2);
            transparentMat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
            transparentMat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
            transparentMat.SetInt("_ZWrite", 0);
            transparentMat.DisableKeyword("_ALPHATEST_ON");
            transparentMat.EnableKeyword("_ALPHABLEND_ON");
            transparentMat.DisableKeyword("_ALPHAPREMULTIPLY_ON");
            transparentMat.color = new Color(1f, 0f, 0f, 0.3f); // Transparent red
            // Find penis colliders
            Collider[] allColliders = male.GetComponentsInChildren<Collider>();
            foreach (var col in allColliders)
            {
                if (penis.IsPenisCollider(col))
                {
                    // Skip standard penisBase, penisMid, penisTip colliders
                    string colNameLower = col.name.ToLower();
                    if (colNameLower.Contains("penisbase") || colNameLower.Contains("penismid") || colNameLower.Contains("penistip"))
                    {
                        SuperController.LogMessage($"CreatePenisColliderViz: Skipped standard collider {col.name} for {male.uid}");
                        continue;
                    }
                    GameObject viz = null;
                    
                    // C# 6.0-compatible type checking
                    if (col is CapsuleCollider)
                    {
                        CapsuleCollider cc = (CapsuleCollider)col;
                        viz = GameObject.CreatePrimitive(PrimitiveType.Capsule);
                        viz.name = "PenisColliderViz_Capsule_" + col.name;
                        viz.transform.SetParent(col.transform, false);
                        viz.transform.localPosition = cc.center;
                        
                        // Account for capsule direction
                        switch (cc.direction)
                        {
                            case 0: // X-axis
                                viz.transform.localRotation = Quaternion.Euler(0f, 0f, 90f);
                                break;
                            case 2: // Z-axis
                                viz.transform.localRotation = Quaternion.Euler(90f, 0f, 0f);
                                break;
                            default: // Y-axis
                                viz.transform.localRotation = Quaternion.identity;
                                break;
                        }
                        
                        // Scale capsule
                        viz.transform.localScale = new Vector3(cc.radius * 2f, cc.height / 2f, cc.radius * 2f);
                    }
                    else if (col is SphereCollider)
                    {
                        SphereCollider sc = (SphereCollider)col;
                        viz = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                        viz.name = "PenisColliderViz_Sphere_" + col.name;
                        viz.transform.SetParent(col.transform, false);
                        viz.transform.localPosition = sc.center;
                        viz.transform.localRotation = Quaternion.identity;
                        viz.transform.localScale = Vector3.one * (sc.radius * 2f);
                    }
                    else if (col is MeshCollider)
                    {
                        MeshCollider mc = (MeshCollider)col;
                        viz = new GameObject("PenisColliderViz_Mesh_" + col.name);
                        viz.transform.SetParent(col.transform, false);
                        viz.transform.localPosition = Vector3.zero;
                        viz.transform.localRotation = Quaternion.identity;
                        viz.transform.localScale = Vector3.one;
                        
                        MeshFilter mf = viz.AddComponent<MeshFilter>();
                        mf.sharedMesh = mc.sharedMesh;
                        
                        MeshRenderer mr = viz.AddComponent<MeshRenderer>();
                        mr.material = transparentMat;
                        mr.enabled = true;
                    }
                    
                    if (viz != null)
                    {
                        // Remove collider from visualization to avoid interfering with physics
                        Collider vizCol = viz.GetComponent<Collider>();
                        if (vizCol != null) UnityEngine.Object.Destroy(vizCol);
                        
                        // Apply transparent material for primitives
                        Renderer r = viz.GetComponent<Renderer>();
                        if (r != null)
                        {
                            r.material = transparentMat;
                            r.enabled = true;
                        }
                        
                        vizList.Add(viz);
                    }
                }
            }
            
            if (vizList.Count > 0)
            {
                penisViz[male] = vizList;
                SuperController.LogMessage($"CreatePenisColliderViz: Created {vizList.Count} visualizations for {male.uid}");
            }
            else
            {
                SuperController.LogMessage($"CreatePenisColliderViz: No CUA penis colliders found for {male.uid}");
            }
        }
        // Hides all penis collider visualizations.
        private void HideAllPenisViz()
        {
            foreach (var pair in penisViz)
            {
                List<GameObject> list = pair.Value;
                if (list != null)
                {
                    for (int i = 0; i < list.Count; i++)
                    {
                        GameObject v = list;
                        if (v != null)
                        {
                            v.SetActive(false);
                            Renderer r = v.GetComponent<Renderer>();
                            if (r != null) r.enabled = false;
                        }
                    }
                }
            }
        }
        // Updates the UI to show settings for the selected orifice.
        private void SelectOrifice(string orificeName)
        {
            selectedOrifice = orificeName;
            ClearUI();
            try
            {
                SetupButton("Mouth Settings", false, delegate { SelectOrifice("Mouth"); });
                SetupButton("Vagina Settings", true, delegate { SelectOrifice("Vagina"); });
                SetupButton("Anus Settings", false, delegate { SelectOrifice("Anus"); });
                SetupButton("Debug", true, ToggleDebugVisibility);
                SetupButton("Penis Colliders", true, TogglePenisColliders);
                AddStatusUIElements();
                if (orifices.ContainsKey(orificeName))
                {
                    Orifice orifice = orifices[orificeName];
                    var triggerScaleSlider = CreateSlider(orifice.triggerScale);
                    uiElements.Add(triggerScaleSlider);
                    sliderStorables.Add(orifice.triggerScale);
                    var triggerOffsetUpSlider = CreateSlider(orifice.triggerOffsetUp);
                    uiElements.Add(triggerOffsetUpSlider);
                    sliderStorables.Add(orifice.triggerOffsetUp);
                    var triggerOffsetForwardSlider = CreateSlider(orifice.triggerOffsetForward);
                    uiElements.Add(triggerOffsetForwardSlider);
                    sliderStorables.Add(orifice.triggerOffsetForward);
                    var proximityScaleSlider = CreateSlider(orifice.proximityScale);
                    uiElements.Add(proximityScaleSlider);
                    sliderStorables.Add(orifice.proximityScale);
                    var showProximityToggle = CreateToggle(orifice.showProximity);
                    uiElements.Add(showProximityToggle);
                    toggleStorables.Add(orifice.showProximity);
                    var infoText = CreateTextField(orifice.info);
                    uiElements.Add(infoText);
                    textFieldStorables.Add(orifice.info);
                }
            }
            catch (Exception e)
            {
                SuperController.LogError("OrificeTriggerManager: Error selecting orifice: " + e.Message);
            }
        }
        // Clears all UI elements from the scene.
        private void ClearUI()
        {
            for (int i = 0; i < uiElements.Count; i++)
            {
                var element = uiElements;
                if (element is UIDynamic) RemoveSpacer(element as UIDynamic);
                if (element is UIDynamicSlider) RemoveSlider(element as UIDynamicSlider);
                if (element is UIDynamicToggle) RemoveToggle(element as UIDynamicToggle);
                if (element is UIDynamicTextField) RemoveTextField(element as UIDynamicTextField);
                if (element is UIDynamicButton) RemoveButton(element as UIDynamicButton);
            }
            uiElements.Clear();
            sliderStorables.Clear();
            toggleStorables.Clear();
            textFieldStorables.Clear();
            buttonElements.Clear();
        }
        // Creates a UI button with the specified label and callback.
        private void SetupButton(string label, bool rightSide, UnityAction action)
        {
            UIDynamicButton button = CreateButton(label, rightSide);
            button.button.onClick.AddListener(action);
            uiElements.Add(button);
            buttonElements.Add(button);
        }
        // Adds status UI elements for displaying penetration and proximity states.
        private void AddStatusUIElements()
        {
            var mouthStatusText = CreateTextField(mouthStatus);
            uiElements.Add(mouthStatusText);
            textFieldStorables.Add(mouthStatus);
            var vaginaStatusText = CreateTextField(vaginaStatus);
            uiElements.Add(vaginaStatusText);
            textFieldStorables.Add(vaginaStatus);
            var anusStatusText = CreateTextField(anusStatus);
            uiElements.Add(anusStatusText);
            textFieldStorables.Add(anusStatus);
            var mouthProxText = CreateTextField(mouthProxStatus);
            uiElements.Add(mouthProxText);
            textFieldStorables.Add(mouthProxStatus);
            var vaginaProxText = CreateTextField(vaginaProxStatus);
            uiElements.Add(vaginaProxText);
            textFieldStorables.Add(vaginaProxStatus);
            var anusProxText = CreateTextField(anusProxStatus);
            uiElements.Add(anusProxText);
            textFieldStorables.Add(anusProxStatus);
        }
        // Updates the penetration status display for a specific orifice.
        public void UpdateStatus(string orificeName)
        {
            JSONStorableString status = null;
            string message = "";
            switch (orificeName)
            {
                case "Mouth":
                    status = mouthStatus;
                    message = "Penis in mouth: ";
                    break;
                case "Vagina":
                    status = vaginaStatus;
                    message = "Penis in vagina: ";
                    break;
                case "Anus":
                    status = anusStatus;
                    message = "Penis in anus: ";
                    break;
            }
            if (status != null && orifices.ContainsKey(orificeName))
            {
                status.val = message + (orifices[orificeName].isPenetrated ? "Yes" : "No");
            }
        }
        // Updates the proximity status display for a specific orifice.
        public void UpdateProxStatus(string orificeName)
        {
            JSONStorableString status = null;
            string message = "";
            switch (orificeName)
            {
                case "Mouth":
                    status = mouthProxStatus;
                    message = "Penis near mouth: ";
                    break;
                case "Vagina":
                    status = vaginaProxStatus;
                    message = "Penis near vagina: ";
                    break;
                case "Anus":
                    status = anusProxStatus;
                    message = "Penis near anus: ";
                    break;
            }
            if (status != null && proximityHandlers.ContainsKey(orificeName))
            {
                ProximityHandler handler = proximityHandlers[orificeName];
                bool inProx = handler != null && handler.isProx;
                status.val = message + (inProx ? "Yes" : "No");
            }
        }
        // Updates all penetration and proximity statuses.
        public void UpdateAllStatuses()
        {
            foreach (var pair in orifices)
            {
                UpdateStatus(pair.Key);
                UpdateProxStatus(pair.Key);
            }
        }
        // Updates statuses every frame.
        private void Update()
        {
            UpdateAllStatuses();
        }
        // Cleans up resources when the script is destroyed, including triggers, orifices, and penis visualizations.
        public void OnDestroy()
        {
            try
            {
                foreach (var pair in orifices)
                {
                    Orifice orifice = pair.Value;
                    if (orifice != null)
                    {
                        if (orifice.enterTriggerCollider != null)
                        {
                            UnityEngine.Object.Destroy(orifice.enterTriggerCollider.gameObject);
                        }
                        if (orifice.proximityTrigger != null)
                        {
                            UnityEngine.Object.Destroy(orifice.proximityTrigger.gameObject);
                        }
                        UnityEngine.Object.Destroy(orifice);
                    }
                }
                orifices.Clear();
                proximityHandlers.Clear();
                triggerHandlers.Clear();
                
                foreach (var pair in penisViz)
                {
                    List<GameObject> list = pair.Value;
                    if (list != null)
                    {
                        for (int i = 0; i < list.Count; i++)
                        {
                            GameObject v = list;
                            if (v != null) UnityEngine.Object.Destroy(v);
                        }
                    }
                }
                penisViz.Clear();
                SuperController.LogMessage("OrificeTriggerManager: Components destroyed");
            }
            catch (Exception e)
            {
                SuperController.LogError("OrificeTriggerManager: Error in OnDestroy: " + e.Message);
            }
            ClearUI();
        }
        // Serializes the script's state to JSON for saving.
        public override JSONClass GetJSON(bool includePhysical = true, bool includeAppearance = true, bool forceStore = true)
        {
            JSONClass jc = base.GetJSON(includePhysical, includeAppearance, forceStore);
            try
            {
                foreach (var pair in orifices)
                {
                    if (pair.Value != null)
                    {
                        jc[pair.Key] = pair.Value.Store("", includePhysical);
                    }
                }
                SuperController.LogMessage("OrificeTriggerManager: JSON saved");
            }
            catch (Exception e)
            {
                SuperController.LogError("OrificeTriggerManager: Serialization error: " + e.Message);
            }
            return jc;
        }
        // Restores the script's state from JSON for loading.
        public override void RestoreFromJSON(JSONClass jc, bool restorePhysical = true, bool restoreAppearance = true, JSONArray presetAtoms = null, bool setMissingToDefault = true)
        {
            base.RestoreFromJSON(jc, restorePhysical, restoreAppearance, presetAtoms, setMissingToDefault);
            try
            {
                foreach (var pair in orifices)
                {
                    if (jc.HasKey(pair.Key) && pair.Value != null)
                    {
                        pair.Value.Load(jc[pair.Key].AsObject, "");
                    }
                }
                UpdateAllStatuses();
                SuperController.LogMessage("OrificeTriggerManager: JSON restored");
            }
            catch (Exception e)
            {
                SuperController.LogError("OrificeTriggerManager: Deserialization error: " + e.Message);
            }
        }
    }
    // Represents a penis on a male atom, managing its colliders for detection.
    public class Penis
    {
        public Atom atom;
        private HashSet<Collider> penisColliders;
        private HashSet<string> penisColliderNames;
        public Penis(Atom atom)
        {
            this.atom = atom;
            penisColliders = new HashSet<Collider>();
            penisColliderNames = new HashSet<string>();
            FindPenisControllers();
            FindCuaPenisColliders();
            
            SuperController.LogMessage($"Penis: Initialized for {atom.uid}. Found colliders: {penisColliders.Count}");
        }
        // Finds penis-related controllers and their colliders.
        private void FindPenisControllers()
        {
            Rigidbody[] rigidbodies = atom.GetComponentsInChildren<Rigidbody>();
            
            foreach (Rigidbody rb in rigidbodies)
            {
                string rbNameLower = rb.name.ToLower();
                bool isPenisPart = false;
                
                if (rbNameLower.Contains("penisbase") || rbNameLower.Contains("penis_base")) isPenisPart = true;
                else if (rbNameLower.Contains("penismid") || rbNameLower.Contains("penis_mid")) isPenisPart = true;
                else if (rbNameLower.Contains("penistip") || rbNameLower.Contains("penis_tip") || rbNameLower.Contains("penistipcontrol")) isPenisPart = true;
                if (isPenisPart)
                {
                    Collider[] colliders = rb.GetComponents<Collider>();
                    foreach (var col in colliders)
                    {
                        penisColliders.Add(col);
                        penisColliderNames.Add(col.name);
                        SuperController.LogMessage($"Penis: Found controller collider: {col.name} from {rb.name}");
                    }
                    Collider[] childColliders = rb.GetComponentsInChildren<Collider>();
                    foreach (var col in childColliders)
                    {
                        if (!penisColliders.Contains(col))
                        {
                            penisColliders.Add(col);
                            penisColliderNames.Add(col.name);
                            SuperController.LogMessage($"Penis: Found child collider: {col.name} from {rb.name}");
                        }
                    }
                }
            }
        }
        // Finds custom (CUA) penis colliders.
        private void FindCuaPenisColliders()
        {
            Collider[] allColliders = atom.GetComponentsInChildren<Collider>();
            
            foreach (var col in allColliders)
            {
                string colNameLower = col.name.ToLower();
                
                if ((colNameLower.Contains("autocollidergen") || colNameLower.Contains("autogen")) &&
                    (colNameLower.Contains("hard") || colNameLower.Contains("soft")) &&
                    !penisColliderNames.Contains(col.name))
                {
                    Transform parent = col.transform.parent;
                    while (parent != null)
                    {
                        if (parent.name.ToLower().Contains("penis"))
                        {
                            penisColliders.Add(col);
                            penisColliderNames.Add(col.name);
                            SuperController.LogMessage($"Penis: Found CUA collider: {col.name}");
                            break;
                        }
                        parent = parent.parent;
                    }
                }
            }
        }
        // Checks if a collider belongs to the penis.
        public bool IsPenisCollider(Collider other)
        {
            if (other == null) return false;
            
            bool isPenisPart = penisColliders.Contains(other);
            
            if (!isPenisPart)
            {
                string otherNameLower = other.name.ToLower();
                isPenisPart = penisColliderNames.Contains(other.name) || 
                             (otherNameLower.Contains("autocollidergen") && otherNameLower.Contains("hard"));
            }
            
            return isPenisPart;
        }
    }
    // Represents an orifice (e.g., Mouth, Vagina, Anus) with trigger and proximity colliders.
    public class Orifice : MonoBehaviour
    {
        public string name;
        public Rigidbody rb;
        public JSONStorableFloat triggerScale;
        public JSONStorableFloat triggerOffsetUp;
        public JSONStorableFloat triggerOffsetForward;
        public JSONStorableFloat proximityScale;
        public JSONStorableBool showProximity;
        public JSONStorableString info;
        public CapsuleCollider enterTriggerCollider;
        public CapsuleCollider proximityTrigger;
        public int penetrationCount;
        public bool isPenetrated { get { return penetrationCount > 0; } }
        public float defaultUp;
        public float defaultForward;
        // Initializes the orifice with specific settings based on its name.
        public virtual void Init(string orificeName, Atom atom)
        {
            name = orificeName;
            try
            {
                string rbName;
                float defaultScale;
                switch (name)
                {
                    case "Mouth":
                        rbName = "ThroatTrigger";
                        defaultScale = 0.03f;
                        defaultUp = 0.01f;
                        defaultForward = 0.07f;
                        break;
                    case "Vagina":
                        rbName = "VaginaTrigger";
                        defaultScale = 0.01f;
                        defaultUp = -0.08f;
                        defaultForward = 0.01f;
                        break;
                    case "Anus":
                        rbName = "pelvis";
                        defaultScale = 0.01f;
                        defaultUp = -0.16f;
                        defaultForward = -0.04f;
                        break;
                    default:
                        rbName = "pelvis";
                        defaultScale = 0.03f;
                        defaultUp = 0f;
                        defaultForward = 0f;
                        break;
                }
                var storable = atom.GetStorableByID(rbName);
                if (storable != null)
                {
                    rb = storable.GetComponent<Rigidbody>();
                }
                if (rb == null)
                {
                    rb = atom.gameObject.AddComponent<Rigidbody>();
                    rb.isKinematic = true;
                    rb.useGravity = false;
                    SuperController.LogMessage("Orifice: Rigidbody created for " + name);
                }
                triggerScale = new JSONStorableFloat("Trigger Scale", defaultScale, 0.01f, 0.5f);
                triggerOffsetUp = new JSONStorableFloat("Trigger Offset Up", 0f, -0.2f, 0.2f);
                triggerOffsetForward = new JSONStorableFloat("Trigger Offset Forward", 0f, -0.2f, 0.2f);
                proximityScale = new JSONStorableFloat("Proximity Scale", defaultScale * 1.5f, 0.01f, 1f);
                showProximity = new JSONStorableBool("Show Proximity Zone", true);
                info = new JSONStorableString("Information", "Orifice: " + name);
                penetrationCount = 0;
                SuperController.LogMessage("Orifice: Initialized " + name);
            }
            catch (Exception e)
            {
                SuperController.LogError("Orifice: Initialization error for " + name + ": " + e.Message);
            }
        }
        // Serializes the orifice's state to JSON.
        public virtual JSONClass Store(string key, bool includePhysical)
        {
            JSONClass jc = new JSONClass();
            try
            {
                jc["triggerScale"] = triggerScale.val.ToString();
                jc["triggerOffsetUp"] = triggerOffsetUp.val.ToString();
                jc["triggerOffsetForward"] = triggerOffsetForward.val.ToString();
                jc["proximityScale"] = proximityScale.val.ToString();
                jc["showProximity"] = showProximity.val.ToString();
                jc["info"] = info.val;
                jc["penetrationCount"] = penetrationCount.ToString();
            }
            catch (Exception e)
            {
                SuperController.LogError("Orifice: Serialization error for " + key + ": " + e.Message);
            }
            return jc;
        }
        // Restores the orifice's state from JSON.
        public virtual void Load(JSONClass jc, string key)
        {
            try
            {
                if (jc.HasKey("triggerScale")) triggerScale.val = float.Parse(jc["triggerScale"]);
                if (jc.HasKey("triggerOffsetUp")) triggerOffsetUp.val = float.Parse(jc["triggerOffsetUp"]);
                if (jc.HasKey("triggerOffsetForward")) triggerOffsetForward.val = float.Parse(jc["triggerOffsetForward"]);
                if (jc.HasKey("proximityScale")) proximityScale.val = float.Parse(jc["proximityScale"]);
                if (jc.HasKey("showProximity")) showProximity.val = bool.Parse(jc["showProximity"]);
                if (jc.HasKey("info")) info.val = jc["info"];
                if (jc.HasKey("penetrationCount")) penetrationCount = int.Parse(jc["penetrationCount"]);
            }
            catch (Exception e)
            {
                SuperController.LogError("Orifice: Deserialization error for " + key + ": " + e.Message);
            }
        }
    }
    // Handles proximity trigger events, tracking when penis colliders enter or exit the proximity zone.
    public class ProximityHandler : MonoBehaviour
    {
        public Orifice orifice;
        public bool on = true;
        public bool isProx = false;
        private float lastLogTime = 0f;
        private const float LogInterval = 2f;
        private HashSet<Collider> penisCollidersInProx = new HashSet<Collider>();
        void OnTriggerEnter(Collider other)
        {
            if (!on || orifice == null) return;
            if (IsPenisCollider(other))
            {
                if (penisCollidersInProx.Add(other))
                {
                    SuperController.LogMessage($"[Prox] Penis entered {gameObject.name} for {orifice.name}");
                    isProx = true;
                    OrificeTriggerManager.singleton.UpdateProxStatus(orifice.name);
                }
            }
        }
        void OnTriggerExit(Collider other)
        {
            if (!on || orifice == null) return;
            if (IsPenisCollider(other))
            {
                if (penisCollidersInProx.Remove(other))
                {
                    SuperController.LogMessage($"[Prox] Penis exited {gameObject.name} for {orifice.name}");
                    isProx = penisCollidersInProx.Count > 0;
                    OrificeTriggerManager.singleton.UpdateProxStatus(orifice.name);
                }
            }
        }
        private bool IsPenisCollider(Collider col)
        {
            if (col == null) return false;
            Atom atom = col.gameObject.GetComponentInParent<Atom>();
            if (atom == null || !OrificeTriggerManager.singleton.penises.ContainsKey(atom)) return false;
            return OrificeTriggerManager.singleton.penises[atom].IsPenisCollider(col);
        }
    }
    // Handles trigger events for an orifice, tracking penetration count.
    public class OrificeTriggerHandler : MonoBehaviour
    {
        public Orifice orifice;
        public bool isActive = true;
        private float lastLogTime = 0f;
        private const float LogInterval = 2f;
        private HashSet<Collider> penisCollidersInTrigger = new HashSet<Collider>();
        void OnTriggerEnter(Collider other)
        {
            if (!isActive || orifice == null) return;
            if (IsPenisCollider(other))
            {
                if (penisCollidersInTrigger.Add(other))
                {
                    orifice.penetrationCount++;
                    SuperController.LogMessage($"[Trig] PENETRATION in {orifice.name}! Count: {orifice.penetrationCount} (collider: {other.name})");
                    OrificeTriggerManager.singleton.UpdateStatus(orifice.name);
                }
            }
        }
        void OnTriggerExit(Collider other)
        {
            if (!isActive || orifice == null) return;
            if (IsPenisCollider(other))
            {
                if (penisCollidersInTrigger.Remove(other))
                {
                    orifice.penetrationCount--;
                    if (orifice.penetrationCount < 0) orifice.penetrationCount = 0;
                    SuperController.LogMessage($"[Trig] Exit from {orifice.name}. Count: {orifice.penetrationCount} (collider: {other.name})");
                    OrificeTriggerManager.singleton.UpdateStatus(orifice.name);
                }
            }
        }
        private bool IsPenisCollider(Collider col)
        {
            if (col == null) return false;
            Atom atom = col.gameObject.GetComponentInParent<Atom>();
            if (atom == null || !OrificeTriggerManager.singleton.penises.ContainsKey(atom)) return false;
            return OrificeTriggerManager.singleton.penises[atom].IsPenisCollider(col);
        }
    }
}