using System;
using Core.Ports;
using KBCore.Refs;
using UnityEngine;
using UnityEngine.AI;
using Random = UnityEngine.Random;

namespace Infrastructure.Unity
{
    [RequireComponent(typeof(Rigidbody))]
    public class NpcController : MonoBehaviour
    {
        [SerializeField] private float moveSpeed = 6f;
        [SerializeField] private float changeDirInterval = 1f;
        [SerializeField] private LayerMask tileLayer;
        
        [Self] [SerializeField] private Rigidbody rb;
        
        private Vector3 _currentDir;
        private float _timer;
        private Func<float> _timeDilationProvider;
        private Action _onPlayerHit;
        
        public void Initialize(Func<float> timeDilationProvider, Action onPlayerHit)
        {
            _onPlayerHit = onPlayerHit;
            _timeDilationProvider = timeDilationProvider;
        }

        private void Awake()
        {
            PickNewDirection();
        }
        
        private void Update()
        {
            _timer += Time.deltaTime;
            if (_timer >= changeDirInterval)
            {
                _timer = 0;
                PickNewDirection();
            }
        }
        
        private void FixedUpdate()
        {
            var dilation = _timeDilationProvider?.Invoke() ?? 1f;
            
            rb.MovePosition(rb.position + _currentDir * (moveSpeed * dilation * Time.fixedDeltaTime));
            
            if (Physics.Raycast(transform.position, Vector3.down, out var hit, 2.0f, tileLayer))
            {
                if (hit.collider.TryGetComponent<ITileView>(out var tileView))
                {
                    tileView.StepOn();
                }
            }
        }

        private bool IsGrounded()
        {
            return Physics.Raycast(transform.position, Vector3.down, out var hit, 2.0f, tileLayer);
        }
        
        private void PickNewDirection()
        {
            var rand = Random.Range(0, 4);
            switch (rand)
            {
                case 0: _currentDir = Vector3.forward; break;
                case 1: _currentDir = Vector3.back; break;
                case 2: _currentDir = Vector3.left; break;
                case 3: _currentDir = Vector3.right; break;
            }
        }

        private void OnCollisionEnter(Collision other)
        {
            if (other.gameObject.TryGetComponent<PlayerController>(out var player))
            {
                _onPlayerHit?.Invoke();
                Destroy(gameObject);
            }
        }
    }
}