using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;

namespace Jankenbots.Prototype
{
    /// <summary>
    /// JANKENBOTS — networked run-around PLAYER avatar (the rigged low-poly
    /// character). This is the foundation for the timed junkyard "gather parts"
    /// phase: each player controls one of these, runs around, and (later) hauls
    /// scrap back to build the bot. Driving the finished bot happens from player
    /// stands, so the avatar and the tread controls are separate systems.
    ///
    /// NETCODE: OWNER-authoritative. Only the owning client reads input and moves
    /// its CharacterController; an <see cref="OwnerAuthNetworkTransform"/> on the
    /// same object replicates the resulting motion to everyone. No host round-trip
    /// on your own movement → it feels responsive.
    ///
    /// ANIMATION: derived LOCALLY on every client from the avatar's measured
    /// horizontal speed (position delta / dt), fed into the Animator's "Speed"
    /// float, which drives an Idle→Walk→Run 1-D blend tree. Because observers
    /// measure the same replicated motion the owner produces, the animation stays
    /// in sync with zero extra network traffic — no NetworkAnimator needed.
    ///
    /// NOTE: reads WASD, same keys as the bot's TreadPart — fine while testing the
    /// avatar in isolation; the real game separates "running" from "driving" via
    /// the (future) player-stand flow, so a player is never doing both at once.
    /// </summary>
    [RequireComponent(typeof(CharacterController))]
    public class PlayerAvatar : NetworkBehaviour
    {
        [Header("Movement")]
        [Tooltip("Run speed in m/s.")]
        public float moveSpeed = 5f;

        [Tooltip("How fast the avatar turns to face its movement direction (deg/s).")]
        public float turnSpeed = 720f;

        [Tooltip("Gravity (m/s^2, negative). Keeps the CharacterController grounded.")]
        public float gravity = -20f;

        [Header("Animation")]
        [Tooltip("Speed value the Animator treats as full-run, for normalising the blend.")]
        public float runAnimSpeed = 5f;

        CharacterController _cc;
        Animator _anim;
        float _vy;                 // vertical velocity (gravity)
        Vector3 _lastPos;
        float _animSpeed;
        static readonly int SpeedHash = Animator.StringToHash("Speed");

        void Awake()
        {
            _cc = GetComponent<CharacterController>();
            _anim = GetComponentInChildren<Animator>();
            _lastPos = transform.position;
        }

        public override void OnNetworkSpawn()
        {
            _lastPos = transform.position;
            // Fan owners out a little so multiple players don't stack on the origin.
            if (IsOwner)
            {
                float a = OwnerClientId * 1.3f;
                transform.position += new Vector3(Mathf.Cos(a), 0f, Mathf.Sin(a)) * (2f + OwnerClientId);
                _lastPos = transform.position;
            }
        }

        void Update()
        {
            if (!IsSpawned) return;

            if (IsOwner) OwnerMove();

            // Animation on EVERY client, from measured horizontal speed.
            Vector3 delta = transform.position - _lastPos;
            delta.y = 0f;
            float measured = delta.magnitude / Mathf.Max(Time.deltaTime, 1e-4f);
            _lastPos = transform.position;
            _animSpeed = Mathf.Lerp(_animSpeed, measured, 12f * Time.deltaTime);
            if (_anim != null) _anim.SetFloat(SpeedHash, _animSpeed);
        }

        void OwnerMove()
        {
            var kb = Keyboard.current;
            float h = 0f, v = 0f;
            if (kb != null)
            {
                if (kb.aKey.isPressed || kb.leftArrowKey.isPressed)  h -= 1f;
                if (kb.dKey.isPressed || kb.rightArrowKey.isPressed) h += 1f;
                if (kb.wKey.isPressed || kb.upArrowKey.isPressed)    v += 1f;
                if (kb.sKey.isPressed || kb.downArrowKey.isPressed)  v -= 1f;
            }

            Vector3 input = new Vector3(h, 0f, v);
            if (input.sqrMagnitude > 1f) input.Normalize();
            Vector3 move = input * moveSpeed;

            if (_cc.isGrounded && _vy < 0f) _vy = -2f;
            _vy += gravity * Time.deltaTime;

            _cc.Move((move + new Vector3(0f, _vy, 0f)) * Time.deltaTime);

            if (move.sqrMagnitude > 0.01f)
            {
                Quaternion target = Quaternion.LookRotation(new Vector3(move.x, 0f, move.z));
                transform.rotation = Quaternion.RotateTowards(transform.rotation, target, turnSpeed * Time.deltaTime);
            }
        }
    }
}
