using System.Collections.Generic;
using NBC;
using UnityEngine;

namespace NBF
{
    [System.Serializable]
    public struct FishingLureCastInput
    {
        [Range(0, 1)] public float power;
        [Range(0, 50)] public float windStrength; // 单位 m/s
        public Vector3 windDirection;
        [Range(5, 30)] public float lureWeight; // 单位 g
        [Range(0.1f, 1f)] public float lineDiameter; // 单位：毫米，0.1mm ~ 1mm
    }

    /// <summary>
    /// 路亚抛竿轨迹动画
    /// </summary>
    public class LureThrowAnim : NTask
    {
        private FPlayer _player;

        [Header("基础参数")] public int maxSimulationSteps = 1000;
        public float simulationDuration = 10f;
        public float timeStep = 0.02f;

        [Header("抛投力度")] public float minThrowPower = 15f;
        public float maxThrowPower = 45f;

        [Header("空气阻力参数")] [Tooltip("阻力系数，非流线钓饵建议 0.8~1.2")]
        public float dragCoefficient = 0.2f;

        [Tooltip("迎风面积，0.005m² ≈ 5cm²")] public float lureArea = 0.001f;


        private FWaterDisplacement _lureHookWaterDisplacement;

        private List<Vector3> _trajectory;

        public float totalDuration = 1.5f; // 总飞行时间
        public float arriveThreshold = 0.01f;

        private float elapsedTime = 0f;
        private bool isMoving = false;
        private Vector3 startOffset = Vector3.zero;

        private Transform _transform;

        public float CurrentDistanceTraveled { get; private set; } = 0f;

        private float _throwStartLineLenght = 0f;


        public LureThrowAnim(FPlayer player)
        {
            _player = player;
        }

        protected override void OnStart()
        {
            _throwStartLineLenght = _player.Data.lineLength;
            _lureHookWaterDisplacement = _player.Gears.Rod.LureHookWaterDisplacement;
            float angle = 25f;
            float radians = angle * Mathf.Deg2Rad;
            Vector3 forwardUp = _player.transform.forward * Mathf.Cos(radians) +
                                _player.transform.up * Mathf.Sin(radians);
            // // 施加力
            // lureHookWaterDisplacement.rigidbody.AddForce(forwardUpDirection * 500, ForceMode.Impulse);
            _transform = _lureHookWaterDisplacement.transform;
            _lureHookWaterDisplacement.rigidbody.isKinematic = true;
            _lureHookWaterDisplacement.rigidbody.useGravity = false;
            FishingLureCastInput baseInput = new FishingLureCastInput
            {
                power = 1f,
                lureWeight = 2.2f,
                windStrength = 0f, // 风力大小
                lineDiameter = 0.14f
            };

            Vector3 startPos = _player.transform.position + Vector3.up * 2.5f;
            // Vector3 startPos = _player.Gears.Rod.rodAsset.lineConnector.position;
            Vector3 throwDir = forwardUp.normalized;
            var trajectory = CalculateTrajectory(baseInput, startPos, throwDir);
            _trajectory = trajectory;
            _trajectory = SimplifyTrajectoryRDP(trajectory, 0.1f);
            // SceneSettings.Instance.LineRenderer.startWidth = 0.1f;
            // SceneSettings.Instance.LineRenderer.endWidth = 0.1f;
            // SceneSettings.Instance.LineRenderer.positionCount = _trajectory.Count;
            // SceneSettings.Instance.LineRenderer.useWorldSpace = true;
            // SceneSettings.Instance.LineRenderer.SetPositions(_trajectory.ToArray());

            elapsedTime = 0f;
            isMoving = true;
            CurrentDistanceTraveled = 0f;

            // 如果不在起点，先移动过去
            if ((_transform.position - _trajectory[0]).magnitude > arriveThreshold)
            {
                startOffset = _trajectory[0] - _transform.position;
            }
            else
            {
                startOffset = Vector3.zero;
            }
        }

        protected override NTaskStatus OnProcess()
        {
            OnMove();
            return base.OnProcess();
        }


        private void MoveDone()
        {
            var rb = _lureHookWaterDisplacement.rigidbody;

            // 强制同步位置和朝向
            rb.position = rb.transform.position;
            rb.rotation = rb.transform.rotation;
            rb.isKinematic = false;
            // 停止物理残留影响
            rb.linearVelocity = Vector3.zero;
            rb.angularVelocity = Vector3.zero;
            rb.useGravity = true;
            Finish();
        }

        private void OnMove()
        {
            if (!isMoving || _trajectory == null || _trajectory.Count < 2) return;
            // Debug.LogError("OnMove");
            // 初始补位阶段（瞬移或平滑补过去）
            if (startOffset.magnitude > arriveThreshold)
            {
                float moveSpeed = startOffset.magnitude / 0.1f;
                Vector3 move = startOffset.normalized * moveSpeed * Time.deltaTime;
                if (move.magnitude >= startOffset.magnitude)
                {
                    _transform.position = _trajectory[0];
                    startOffset = Vector3.zero;
                }
                else
                {
                    _transform.position += move;
                    startOffset -= move;
                }

                return;
            }

            elapsedTime += Time.deltaTime;
            float t = Mathf.Clamp01(elapsedTime / totalDuration);

            // 插值路径
            int segmentCount = _trajectory.Count - 1;
            float totalSegmentLength = segmentCount;
            float pathT = t * totalSegmentLength;
            int index = Mathf.FloorToInt(pathT);

            if (index >= _trajectory.Count - 1)
            {
                _transform.position = _trajectory[^1];
                isMoving = false;
                CurrentDistanceTraveled = CalculateTotalDistance(_trajectory);
                MoveDone();
                return;
            }

            float localT = pathT - index;
            Vector3 p0 = _trajectory[index];
            Vector3 p1 = _trajectory[index + 1];
            _transform.position = Vector3.Lerp(p0, p1, localT);

            var distance = Vector3.Distance(_lureHookWaterDisplacement.transform.position,
                _player.Gears.Rod.rodAsset.lineConnector.position);
            if (distance > _throwStartLineLenght)
            {
                _throwStartLineLenght = distance;
                _player.Data.lineLength = _throwStartLineLenght + 0.5f;
            }
            // _throwStartLineLenght 
        }

        float CalculateTotalDistance(List<Vector3> points)
        {
            float dist = 0f;
            for (int i = 1; i < points.Count; i++)
                dist += Vector3.Distance(points[i - 1], points[i]);
            return dist;
        }

        public List<Vector3> CalculateTrajectory(FishingLureCastInput input, Vector3 startPosition,
            Vector3 castDirection)
        {
            List<Vector3> trajectory = new List<Vector3>();

            Vector3 position = startPosition;
            Vector3 direction = castDirection.normalized;
            float throwPower = Mathf.Lerp(minThrowPower, maxThrowPower, input.power);
            Vector3 velocity = direction * throwPower;

            float lureMass = input.lureWeight / 1000f; // 转 kg
            Vector3 windDir = input.windDirection.normalized;
            float windStrength = input.windStrength;

            float currentTime = 0f;
            int steps = 0;
            totalDuration = 0;
            while (currentTime < simulationDuration && steps < maxSimulationSteps)
            {
                if (position.y <= 0f) break;

                // 模拟风力逐渐生效
                float windInfluenceFactor = Mathf.Clamp01(currentTime / 1.5f); // 1.5秒内增长
                Vector3 windVelocity = windDir * windStrength * windInfluenceFactor;

                // 真实空气阻力模型
                Vector3 relVelocity = velocity - windVelocity;

                // 空气阻力
                float dragMag = 0.5f * PhysicsHelper.AirDensity *
                                relVelocity.sqrMagnitude *
                                dragCoefficient * lureArea;

                // --- 钓线空气阻力模拟 ---
                // 假设飞行中展开的线长度近似为当前位置的XZ平面长度
                float lineLength = Vector3.Distance(new Vector3(position.x, 0, position.z),
                    new Vector3(startPosition.x, 0, startPosition.z));
                float lineRadius = input.lineDiameter / 2000f; // mm转m再除以2得到半径

                // 钓线的迎风面积估算：长度 * 直径
                float lineArea = lineLength * (lineRadius * 2f); // 近似为圆柱体侧面积的一部分

                // 简化模型：线的附加空气阻力方向与当前速度方向相反
                float lineDragMag = 0.5f * PhysicsHelper.AirDensity * velocity.sqrMagnitude * dragCoefficient *
                                    lineArea;
                Vector3 lineDragForce = -velocity.normalized * lineDragMag;


                Vector3 dragForce = -relVelocity.normalized * dragMag;

                // 合力 = 重力 + 空气阻力
                // Vector3 acceleration = (Physics.gravity + dragForce / lureMass);
                Vector3 totalForce = dragForce + lineDragForce;
                // 合力 = 重力 + 空气阻力 + 线阻力
                Vector3 acceleration = (Physics.gravity + totalForce / lureMass);


                velocity += acceleration * timeStep;
                position += velocity * timeStep;

                trajectory.Add(position);
                currentTime += timeStep;
                steps++;
            }

            totalDuration = currentTime;
            return trajectory;
        }


        public static List<Vector3> SimplifyTrajectoryRDP(List<Vector3> points, float tolerance)
        {
            if (points == null || points.Count < 3)
                return new List<Vector3>(points);

            List<Vector3> result = new List<Vector3>();
            SimplifySection(points, 0, points.Count - 1, tolerance, result);
            result.Add(points[points.Count - 1]);
            return result;
        }

        private static void SimplifySection(List<Vector3> points, int start, int end, float tolerance,
            List<Vector3> result)
        {
            if (end <= start + 1)
                return;

            float maxDistance = -1f;
            int index = -1;
            Vector3 startPoint = points[start];
            Vector3 endPoint = points[end];

            for (int i = start + 1; i < end; i++)
            {
                float distance = PerpendicularDistance(points[i], startPoint, endPoint);
                if (distance > maxDistance)
                {
                    maxDistance = distance;
                    index = i;
                }
            }

            if (maxDistance > tolerance)
            {
                SimplifySection(points, start, index, tolerance, result);
                result.Add(points[index]);
                SimplifySection(points, index, end, tolerance, result);
            }
        }

        private static float PerpendicularDistance(Vector3 point, Vector3 lineStart, Vector3 lineEnd)
        {
            if (lineStart == lineEnd) return Vector3.Distance(point, lineStart);
            Vector3 projected = Vector3.Project(point - lineStart, lineEnd - lineStart);
            Vector3 closest = lineStart + projected;
            return Vector3.Distance(point, closest);
        }
    }
}