using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

namespace NBF
{
    public enum LineType
    {
        Hand,
        HandDouble,
        Spinning,
        SpinningFloat,
    }

    public class FLine : FGearBase
    {
        [SerializeField] public LineType LineType;


        [Header("References")] [SerializeField]
        private Transform anchorTransform;

        [SerializeField] private FishingLineNode[] logicalNodes = Array.Empty<FishingLineNode>();

        [SerializeField] private VerletRope ropePrefab;
        // public JointPinchController PinchController;

        public bool IsRopeLimit { get; private set; }

        protected override void OnInit()
        {
            // var tipRb = Rod.Asset.LineConnectorRigidbody;
            // anchorTransform = tipRb.transform;
            //
            // GetComponentsInChildren<Transform>(includeInactive: true).ToList().ForEach(delegate(Transform i)
            // {
            //     i.gameObject.SetActive(true);
            // });
        }

        private void Awake()
        {
        }

        private void Start()
        {
            InitRopes();
            GetComponentsInChildren<Transform>(includeInactive: true).ToList().ForEach(delegate(Transform i)
            {
                i.gameObject.SetActive(true);
            });
        }

        private void FixedUpdate()
        {
            UpdateAnchorNode();
            UpdateBreakCountdown(Time.fixedDeltaTime);
        }

        #region Start Node

        private void ConfigureStartNode()
        {
            if (logicalNodes == null || logicalNodes.Length == 0 || logicalNodes[0] == null)
            {
                return;
            }

            var startNode = logicalNodes[0];
            startNode.Type = FishingLineNode.NodeType.Start;

            if (startNode.Body != null)
            {
                startNode.Body.isKinematic = true;
                startNode.Body.interpolation = RigidbodyInterpolation.Interpolate;
                startNode.Body.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
            }

            UpdateAnchorNode();
        }

        private void UpdateAnchorNode()
        {
            if (anchorTransform == null || logicalNodes == null || logicalNodes.Length == 0 || logicalNodes[0] == null)
            {
                return;
            }

            var startNode = logicalNodes[0];
            startNode.transform.SetPositionAndRotation(anchorTransform.position, anchorTransform.rotation);

            if (startNode.Body != null)
            {
                if (!startNode.Body.isKinematic)
                {
                    startNode.Body.linearVelocity = Vector3.zero;
                    startNode.Body.angularVelocity = Vector3.zero;
                }
            }
        }

        #endregion

        #region Rope

        private Transform _ropeRoot;

        /// <summary>
        /// 设置指定逻辑段的配置长度。
        /// segmentIndex 为 0 时表示第一段；大于 0 时表示对应逻辑节点到下一个逻辑节点的线长。
        /// </summary>
        public void SetLenght(float length, int index = 0)
        {
            ConfigureStartNode();
            var node = logicalNodes[index + 1];
            if (node != null)
            {
                node.SetLenght(length);
            }
        }

        public void SetRopeLimit(bool limit)
        {
            Debug.Log($"set rope limit {limit}");
            IsRopeLimit = limit;
            foreach (var node in logicalNodes)
            {
                if (node.Joint == null) continue;
                node.SetJointLenght(node.Lenght);
            }
        }


        private void InitRopes()
        {
            var root = new GameObject("RopeRoot");
            _ropeRoot = root.transform;
            _ropeRoot.SetParent(transform);
            CreateRopes();
        }

        private void CreateRopes()
        {
            foreach (var node in LogicalNodes)
            {
                if (!node.PreNode) continue;
                var rope = CreateRope(node.PreNode.Body, node.Body);
                node.SetRope(rope);
                node.SetLenght(0.1f);
            }
        }


        public VerletRope CreateRope(Rigidbody startRigidbody, Rigidbody endRigidbody, Vector3 startLocalPos = default,
            Vector3 endLocalPos = default)
        {
            var rope = Instantiate(ropePrefab, _ropeRoot);
            //rope.InitializeRope();
            rope.ropeStartPoint = startRigidbody.transform.TransformPoint(startLocalPos);
            rope.ropeEndPoint = endRigidbody.transform.TransformPoint(endLocalPos);
            rope.Enable();
            rope.ConnectStartRigidbody(startRigidbody, startLocalPos);
            rope.ConnectEndRigidbody(endRigidbody, endLocalPos);
            return rope;
        }

        #endregion

        #region LineNode

        /// <summary>
        /// 当前配置的逻辑节点只读列表。
        /// 外部可读取节点顺序，但不应直接修改数组内容。
        /// </summary>
        public IReadOnlyList<FishingLineNode> LogicalNodes => logicalNodes;

        /// <summary>
        /// 根据类型获取逻辑节点类型
        /// </summary>
        /// <param name="nodeType"></param>
        /// <returns></returns>
        public FishingLineNode GetLogicalNode(FishingLineNode.NodeType nodeType)
        {
            foreach (var fishingLineNode in logicalNodes)
            {
                if (fishingLineNode.Type == nodeType)
                {
                    return fishingLineNode;
                }
            }

            return null;
        }

        /// <summary>
        /// 获取指定顺序索引的逻辑节点。
        /// 索引基于 logicalNodes 配置顺序；超出范围或节点为空时返回 null。
        /// </summary>
        public FishingLineNode GetLogicalNode(int logicalIndex)
        {
            if (logicalNodes == null || logicalIndex < 0 || logicalIndex >= logicalNodes.Length)
            {
                return null;
            }

            return logicalNodes[logicalIndex];
        }

        /// <summary>
        /// 获取当前起点逻辑节点。
        /// 会返回配置顺序中第一个非空节点。
        /// </summary>
        public FishingLineNode GetStartNode()
        {
            return FindFirstValidLogicalNode();
        }

        /// <summary>
        /// 获取当前终点逻辑节点。
        /// 会返回配置顺序中最后一个非空节点。
        /// </summary>
        public FishingLineNode GetEndNode()
        {
            return FindLastValidLogicalNode();
        }

        private FishingLineNode FindFirstValidLogicalNode()
        {
            if (logicalNodes == null)
            {
                return null;
            }

            for (var i = 0; i < logicalNodes.Length; i++)
            {
                if (logicalNodes[i] != null)
                {
                    return logicalNodes[i];
                }
            }

            return null;
        }

        private FishingLineNode FindLastValidLogicalNode()
        {
            if (logicalNodes == null)
            {
                return null;
            }

            for (var i = logicalNodes.Length - 1; i >= 0; i--)
            {
                if (logicalNodes[i] != null)
                {
                    return logicalNodes[i];
                }
            }

            return null;
        }

        #endregion

        #region 极限判定

        /// <summary>
        /// 当前逻辑链总长度超出配置总长度的部分，小于等于零时记为 0。
        /// </summary>
        [Header("Limit Detection")]
        public float CurrentStretchLength { get; private set; }

        /// <summary>
        /// 总长度
        /// </summary>
        public float TotalLength { get; private set; }

        [Min(0f)]
        // 极限判定的长度容差，允许链路在总长或单段长度上存在少量误差。
        [SerializeField]
        private float lengthLimitTolerance = 0.01f;

        [Min(0f)]
        // 达到极限后，只有当前超长值大于该阈值时，才开始进入断线候选计时。
        [SerializeField]
        private float breakStretchThreshold = 0.3f;

        [Min(0f)]
        // 断线候选状态允许持续的最大时间；超过后会发出一次断线消息。
        [SerializeField]
        private float breakLimitDuration = 3f;

        /// <summary>
        /// 当鱼线达到断线条件时发出的一次性消息。
        /// 外部可订阅该事件，在回调中执行切线、播放表现或状态切换。
        /// </summary>
        public event Action<FLine> OnLineBreakRequested;

        /// <summary>
        /// 当前是否处于极限状态。
        /// 只要整链超出总长度容差，或任一逻辑段超出单段容差，即认为到达极限。
        /// </summary>
        public bool IsAtLimit { get; private set; }

        /// <summary>
        /// 当前断线候选状态的累计时间。
        /// 只有在处于极限状态，且 CurrentStretchLength 大于断线阈值时才会累加；否则重置为 0。
        /// </summary>
        public float LimitStateTime { get; private set; }

        /// <summary>
        /// 当前极限断线消息是否已经发出过。
        /// 在退出断线候选状态前只会发一次，避免重复通知。
        /// </summary>
        public bool HasBreakNotificationSent { get; private set; }

        /// <summary>
        /// 当前拉力极限百分比。
        /// 当超长值小于等于 lengthLimitTolerance 时为 0；
        /// 当超长值大于等于 breakStretchThreshold 时为 100；
        /// 中间区间按线性比例映射，供 UI 显示使用。
        /// </summary>
        public float CurrentBreakStretchPercent => EvaluateBreakStretchPercent(CurrentStretchLength);

        /// <summary>
        /// 当前是否正在进行断线候选计时。
        /// </summary>
        public bool IsBreakCountdownActive => IsAtLimit && CurrentStretchLength > breakStretchThreshold;

        private float EvaluateBreakStretchPercent(float stretchLength)
        {
            if (stretchLength <= lengthLimitTolerance)
            {
                return 0f;
            }

            if (stretchLength >= breakStretchThreshold)
            {
                return 100f;
            }

            if (breakStretchThreshold <= lengthLimitTolerance)
            {
                return 100f;
            }

            return Mathf.InverseLerp(lengthLimitTolerance, breakStretchThreshold, stretchLength) * 100f;
        }

        private void SetLimitState(bool isAtLimit)
        {
            IsAtLimit = isAtLimit;
        }

        private void UpdateBreakCountdown(float deltaTime)
        {
            if (logicalNodes == null || logicalNodes.Length == 0)
            {
                SetLimitState(false);
                ResetLimitState();
                return;
            }

            CurrentStretchLength = 0;
            TotalLength = 0;
            //计算长度
            foreach (var node in logicalNodes)
            {
                CurrentStretchLength += node.StretchLength;
                TotalLength += node.Lenght;
            }

            SetLimitState(CurrentStretchLength > lengthLimitTolerance);

            if (!IsBreakCountdownActive)
            {
                LimitStateTime = 0f;
                HasBreakNotificationSent = false;
                return;
            }

            LimitStateTime += Mathf.Max(0f, deltaTime);
            if (HasBreakNotificationSent || LimitStateTime < breakLimitDuration)
            {
                return;
            }

            HasBreakNotificationSent = true;
            NotifyLineBreakRequested();
        }

        /// <summary>
        /// 发出鱼线达到断线条件的消息。
        /// 这里预留给外部订阅，当前不在求解器内部直接执行断线逻辑。
        /// </summary>
        private void NotifyLineBreakRequested()
        {
            OnLineBreakRequested?.Invoke(this);
        }

        private void ResetLimitState()
        {
            CurrentStretchLength = 0f;
            IsAtLimit = false;
            LimitStateTime = 0f;
            HasBreakNotificationSent = false;
        }

        #endregion
    }
}