using System.Collections.Generic;
using UnityEngine;

public class NPCMovement : MonoBehaviour
{
    private Pathfinder _pathfinder;
    private MoveController _moveController;
    private FlipController _flipController;

    private List<Vector2Int> _path;
    private int _pathIndex;
    private float _stuckTimer;

    public bool IsArrived => _path == null || _pathIndex >= _path.Count;
    public bool IsStuck => _stuckTimer > 2f;

    public void Initialize(Pathfinder pathfinder)
    {
        _pathfinder = pathfinder;
        _moveController = GetComponent<MoveController>();
        _flipController = GetComponent<FlipController>();
    }

    public void SetSpeed(float speed)
    {
        _moveController.SetSpeed(speed);
    }

    public void Stop()
    {
        _moveController.Stop();
        _path = null;
    }

    // Find path to random destination
    public bool FindNewPath()
    {
        var start = GetCurrentTile();
        var end = _pathfinder.GetRandomWalkableTile(0, start, 5);
        return SetPath(_pathfinder.GetPath(start, end));
    }

    // Find path toward a specific target
    public bool FindPathTo(Transform target)
    {
        var start = GetCurrentTile();
        var targetTile = _pathfinder.WorldToTile(target.position);
        if (!_pathfinder.IsWalkable(targetTile))
            targetTile = _pathfinder.FindNearestWalkable(targetTile);

        return SetPath(_pathfinder.GetPath(start, targetTile));
    }

    // Follow path each frame
    public void FollowPath()
    {
        if (IsArrived) return;

        // Snap to nearest walkable if on blocked tile
        var currentTile = _pathfinder.WorldToTile(transform.position);
        if (!_pathfinder.IsWalkable(currentTile))
        {
            var nearest = _pathfinder.FindNearestWalkable(currentTile);
            transform.position = _pathfinder.TileToWorld(nearest);
            _path = null;
            return;
        }

        var targetWorld = _pathfinder.TileToWorld(_path[_pathIndex]);
        _moveController.MoveTo(targetWorld);
        _flipController.SetDirection(targetWorld.x - transform.position.x);

        if (_moveController.ReachedTarget(targetWorld, 0.15f))
        {
            _pathIndex++;
            _stuckTimer = 0;
        }
        else
        {
            _stuckTimer += Time.deltaTime;
        }
    }

    public void FaceTarget(Transform target)
    {
        _flipController.SetDirection(target.position.x - transform.position.x);
    }

    public void ResetStuck()
    {
        _stuckTimer = 0;
    }

    public bool IsPositionValid()
    {
        var pos = transform.position;
        return !float.IsNaN(pos.x) && !float.IsInfinity(pos.x);
    }

    private Vector2Int GetCurrentTile()
    {
        var tile = _pathfinder.WorldToTile(transform.position);
        if (!_pathfinder.IsWalkable(tile))
            tile = _pathfinder.FindNearestWalkable(tile);
        return tile;
    }

    private bool SetPath(List<Vector2Int> path)
    {
        if (path == null || path.Count < 2)
        {
            _path = null;
            return false;
        }
        _path = path;
        _pathIndex = 1;
        _stuckTimer = 0;
        return true;
    }
}
