using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using KSP.UI.Screens;

namespace KerbalEyelidMod
{
    // Startup.EveryScene ensures the UI survives reverts and scene changes
    [KSPAddon(KSPAddon.Startup.Flight, false)]
    public class EyelidMaster : MonoBehaviour
    {
        private static ApplicationLauncherButton _btn;
        private bool _draw = false;
        private Rect _rect = new Rect(100, 100, 220, 350);

        void Start()
        {
            GameEvents.onGUIApplicationLauncherReady.Add(SetupBtn);
            GameEvents.onGUIApplicationLauncherDestroyed.Add(RemoveBtn);
        }

        private void SetupBtn()
        {
            if (_btn == null && ApplicationLauncher.Ready)
            {
                _btn = ApplicationLauncher.Instance.AddModApplication(
                () => { _draw = true; }, () => { _draw = false; },
                null, null, null, null,
                ApplicationLauncher.AppScenes.FLIGHT,
                GameDatabase.Instance.GetTexture("KerbalEyelids/icon", false));
            }
        }

        private void RemoveBtn() { if (_btn != null) { ApplicationLauncher.Instance.RemoveModApplication(_btn); _btn = null; } }

        void OnDestroy()
        {
            GameEvents.onGUIApplicationLauncherReady.Remove(SetupBtn);
            GameEvents.onGUIApplicationLauncherDestroyed.Remove(RemoveBtn);
            // Don't remove the button here, KSP handles it or it stays for next flight
        }

        void OnGUI()
        {
            if (_draw) _rect = GUILayout.Window(12345, _rect, Win, "Kerbal Sleep Tool");
        }

        void Win(int id)
        {
            GUILayout.BeginVertical();
            var kerbals = FindObjectsOfType<Kerbal>();
            if (kerbals.Length == 0) GUILayout.Label("No Kerbals found.");

            foreach (var k in kerbals)
            {
                var c = k.gameObject.GetComponent<EyelidLogic>();
                if (c == null) continue;
                GUILayout.BeginHorizontal();
                GUILayout.Label(k.name, GUILayout.Width(110));
                if (GUILayout.Button(c.sleeping ? "WAKE" : "SLEEP")) c.sleeping = !c.sleeping;
                GUILayout.EndHorizontal();
            }
            if (GUILayout.Button("Close")) _draw = false;
            GUILayout.EndVertical();
            GUI.DragWindow();
        }

        void Update()
        {
            // Re-scan for Kerbals every second to catch them after a revert/EVA
            if (Time.frameCount % 60 == 0)
            {
                foreach (var k in FindObjectsOfType<Kerbal>())
                {
                    if (k.gameObject.GetComponent<EyelidLogic>() == null)
                        k.gameObject.AddComponent<EyelidLogic>();
                }
            }
        }
    }

    public class EyelidLogic : MonoBehaviour
    {
        public bool sleeping = false;
        private GameObject _l, _r;
        private Transform _lTarget, _rTarget;
        private float _blinkFactor = 0f;
        private float _timer = 3f;
        private Animator _kerbalAnim;

        void Start()
        {
            _kerbalAnim = GetComponentInChildren<Animator>();
            var meshes = GetComponentsInChildren<SkinnedMeshRenderer>(true);
            foreach (var smr in meshes)
            {
                if (smr.name.ToLower().Contains("eyeball"))
                {
                    GameObject lid = new GameObject("Eyelid_" + smr.name);

                    // Attach directly to the eye bone
                    lid.transform.SetParent(smr.transform, false);
                    lid.transform.localPosition = new Vector3(0, 0, 0.003f); // Push forward slightly
                    lid.transform.localRotation = Quaternion.identity;
                    lid.layer = 16;

                    MeshFilter mf = lid.AddComponent<MeshFilter>();
                    MeshRenderer mr = lid.AddComponent<MeshRenderer>();
                    mf.mesh = smr.sharedMesh;

                    mr.material = new Material(Shader.Find("KSP/Emissive/Diffuse"));
                    mr.material.mainTexture = GameDatabase.Instance.GetTexture("KerbalEyelids/bada55", false);

                    // LIGHT YELLOW GREEN (Lighter & More Yellow)
                    mr.material.color = new Color(0.82f, 0.96f, 0.38f);

                    if (smr.name.ToLower().Contains("left")) { _l = lid; _lTarget = smr.transform; }
                    else { _r = lid; _rTarget = smr.transform; }

                    lid.SetActive(false);
                }
            }
        }

        void LateUpdate()
        {
            // High G-Force check
            Vessel v = FlightGlobals.ActiveVessel;
            bool gBlackout = (v != null && v.geeForce > 7.0);

            if (sleeping || gBlackout)
            {
                _blinkFactor = Mathf.MoveTowards(_blinkFactor, 1f, Time.deltaTime * 5f);
                if (_kerbalAnim != null) _kerbalAnim.enabled = false;
            }
            else
            {
                _blinkFactor = Mathf.MoveTowards(_blinkFactor, 0f, Time.deltaTime * 5f);
                if (_kerbalAnim != null) _kerbalAnim.enabled = true;

                _timer -= Time.deltaTime;
                if (_timer <= 0)
                {
                    StartCoroutine(DoBlink());
                    _timer = UnityEngine.Random.Range(2f, 6f);
                }
            }

            UpdateLid(_l, _lTarget);
            UpdateLid(_r, _rTarget);
        }

        void UpdateLid(GameObject lid, Transform target)
        {
            if (lid == null || target == null) return;

            // Constrain position and rotation to the eye bone every frame
            lid.transform.position = target.position + (target.forward * 0.003f);
            lid.transform.rotation = target.rotation;

            // Scale to "close" the eye
            float s = 1.015f * _blinkFactor;
            lid.transform.localScale = new Vector3(1.015f, s, s);

            lid.SetActive(_blinkFactor > 0.01f);
        }

        IEnumerator DoBlink()
        {
            if (sleeping) yield break;
            while (_blinkFactor < 1f && !sleeping) { _blinkFactor += Time.deltaTime * 25f; yield return null; }
            while (_blinkFactor > 0f && !sleeping) { _blinkFactor -= Time.deltaTime * 25f; yield return null; }
            if (!sleeping) _blinkFactor = 0f;
        }
    }
}