please inspect, diagnose, and then fix / refactor my enemies pathing behaviour in order to fix its current issue of not going after the player whatsoever, for some reason there is never a trigger for it to get out of idle state

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.PriorityQueue;

enum AnimationState {
    IDLE, WALKING, ATTACKING, DAMAGED, DYING
}

class Enemy {

    float x, y;
    float speed = 1.5;
    int health;
    int maxHealth = 100;


    float respawnTime;
    float respawnTimer;

    List<PVector> path;
    int pathIndex;
    int updatePathInterval = 60; // Update path every 60 frames
    int frameCount;

    boolean active;
    AnimationState currentState = AnimationState.IDLE;
    HashMap<AnimationState, Animation> animations = new HashMap<>();
    Animation currentAnim;
    int stateTimer = 0;
    int damagedDuration = 30; 
    int dyingDuration = 60; 
    int attackingDuration = 55; //Duration for attacking state in frames (11 frames * 5 frame delay)
    boolean hasDealtDamage = false; //to ensure damage is dealt only once per attack
    

    PImage spriteSheet;
    int spriteWidth = 90;
    int spriteHeight = 64;
    Player player; // Reference to the player

    Enemy(float respawnTime, Player playerRef) {
        this.respawnTime = respawnTime;
        this.respawnTimer = respawnTime;
        this.health = maxHealth;
        this.player = playerRef;
        this.spriteSheet = random(1) < 0.5 ? enemySpriteSheet1 : enemySpriteSheet2;

        animations.put(AnimationState.ATTACKING, new Animation(0, 11, 5, false));
        animations.put(AnimationState.DYING, new Animation(1, 13, 5, false));
        animations.put(AnimationState.DAMAGED, new Animation(2, 4, 5, false));
        animations.put(AnimationState.IDLE, new Animation(3, 8, 5, true));
        animations.put(AnimationState.WALKING, new Animation(4, 10, 5, true));

        // Set the initial animation
        currentAnim = animations.get(currentState);
        currentAnim.reset();
        respawn(); //this takes care of initital position
    }


void update(Tile[][] map ) {

    if (!active) {//downtime after being killed
        respawnTimer -= 1.0 / frameRate;
        if (respawnTimer <= 0) {
                active = true;
                respawn();
        }
        return;
    }
            switch (currentState) {
            case DAMAGED:
            case DYING:
            case ATTACKING:
                handleState(map);
                break;
            default:
                handleMovement(map);
                break;
        }

        currentAnim.update();   
    }

    void handleState(Tile[][] map) {
        stateTimer--;
        if (stateTimer <= 0) {
            switch (currentState) {
                case DYING:
                    active = false;
                    respawnTimer = respawnTime;
                    break;
                case ATTACKING:
                    setState(AnimationState.IDLE);
                    break;
                case DAMAGED:
                    setState(AnimationState.WALKING);
                    break;
            }
        }

        // Specific actions for states
        if (currentState == AnimationState.ATTACKING && !hasDealtDamage) {
            checkPlayerDamage();
        }
    }

void handleMovement(Tile[][] map) {
        // Increment frame count and update path if needed
        frameCount++;
        if (frameCount >= updatePathInterval) {
            updatePath(map);
            frameCount = 0;
        }

        // Check distance to player
        float distanceToPlayer = dist(x, y, player.x, player.y);
        if (distanceToPlayer < TILE_SIZE * 1.5f) { // Attack range
            attack();
            return;
        }

        // Move along the path if it exists
        if (path != null && !path.isEmpty() && pathIndex < path.size()) {
            PVector target = path.get(pathIndex);
            float dx = target.x - x;
            float dy = target.y - y;
            float distance = sqrt(dx * dx + dy * dy);

            if (distance < speed) {
                // Reached the current target node
                pathIndex++;
                if (pathIndex >= path.size()) {
                    path = null;
                    setState(AnimationState.IDLE);
                }
            } else {
                // Move towards the target node
                float ratio = speed / distance;
                float newX = x + dx * ratio;
                float newY = y + dy * ratio;

                // Check for collision before moving
                if (!isCollision(newX, newY, map)) {
                    x = newX;
                    y = newY;
                    setState(AnimationState.WALKING);
                } else {
                    // Collision detected, recalculate path
                    updatePath(map);
                }
            }
        } else {
            setState(AnimationState.IDLE);
        }
    }

void setState(AnimationState newState) {
        if (currentState != newState) {
            currentState = newState;
            currentAnim = animations.get(currentState);
            currentAnim.reset();

            // Set state timers based on the new state
            switch (newState) {
                case DAMAGED:
                    stateTimer = damagedDuration;
                    break;
                case DYING:
                    stateTimer = dyingDuration;
                    break;
                case ATTACKING:
                    stateTimer = attackingDuration;
                    hasDealtDamage = false; // Reset damage flag
                    break;
                default:
                    // No timer needed for IDLE and WALKING
                    break;
            }
        }
    }

    void attack() {
        setState(AnimationState.ATTACKING);
        soundManager.playEnemyAttack();
    }

    void checkPlayerDamage( ) {
        if (dist(player.x, player.y, x, y) < TILE_SIZE && player.canTakeDamage() && isAlive() && !hasDealtDamage) {
            player.takeDamage();
            hasDealtDamage = true;
            hitFlash();
            // Note: You might want to trigger screen shake and red flash from here,
            // or implement a method in the main class that the Enemy can call.
        }
    }

    void updatePath(Tile[][] map) {
        int startX = floor(x / TILE_SIZE);
        int startY = floor(y / TILE_SIZE);
        int endX = floor(player.x / TILE_SIZE);
        int endY = floor(player.y / TILE_SIZE);

        path = aStar(map, startX, startY, endX, endY);
        pathIndex = 0;
    }

   List<PVector> aStar(Tile[][] map, int startX, int startY, int goalX, int goalY) {
        PriorityQueue<Node> openSet = new PriorityQueue<>();
        boolean[][] closedSet = new boolean[map.length][map[0].length];
        Node[][] nodeMap = new Node[map.length][map[0].length];

        // Initialize nodes
        for (int i = 0; i < map.length; i++) {
            for (int j = 0; j < map[0].length; j++) {
                nodeMap[i][j] = new Node(i, j);
            }
        }

        Node start = nodeMap[startX][startY];
        Node goal = nodeMap[goalX][goalY];
        start.g = 0;
        start.f = heuristic(start, goal);
        openSet.add(start);

        while (!openSet.isEmpty()) {
            Node current = openSet.poll();

            if (current.equals(goal)) {
                return reconstructPath(current);
            }

            closedSet[current.x][current.y] = true;

            // Explore neighbors (4-directional)
            for (int[] dir : new int[][] { {0, 1}, {1, 0}, {0, -1}, {-1, 0} }) {
                int neighborX = current.x + dir[0];
                int neighborY = current.y + dir[1];

                // Check map bounds
                if (neighborX < 0 || neighborX >= map.length || neighborY < 0 || neighborY >= map[0].length) {
                    continue;
                }

                // Skip if already evaluated or blocked
                if (closedSet[neighborX][neighborY] || map[neighborX][neighborY].type != TileType.EMPTY) {
                    continue;
                }

                Node neighbor = nodeMap[neighborX][neighborY];
                float tentativeG = current.g + 1; // Assuming uniform cost

                if (tentativeG < neighbor.g) {
                    neighbor.parent = current;
                    neighbor.g = tentativeG;
                    neighbor.f = neighbor.g + heuristic(neighbor, goal);

                    if (!openSet.contains(neighbor)) {
                        openSet.add(neighbor);
                    }
                }
            }
        }

        return null; // No path found
    }


    float heuristic(Node a, Node b) {
        return abs(a.x - b.x) + abs(a.y - b.y);
    }

    List<PVector> reconstructPath(Node goal) {
        List<PVector> path = new ArrayList<>();
        Node current = goal;

        while (current != null) {
            path.add(new PVector(current.x * TILE_SIZE + TILE_SIZE / 2, current.y * TILE_SIZE + TILE_SIZE / 2));
            current = current.parent;
        }
        Collections.reverse(path);
        return path;
    }

    

     void takeDamage(int damage) {
        health -= damage;
        if (!isAlive()) {
            setState(AnimationState.DYING);
            soundManager.playEnemyDie();
        } else {
            setState(AnimationState.DAMAGED);
            soundManager.playEnemyHit();
        }
    }

    void respawn() {
        setState(AnimationState.IDLE);
        active = true;
        health = maxHealth;
        PVector safePosition = findSafeSpawnPosition();
        x = safePosition.x;
        y = safePosition.y;
    }

    boolean isAlive() {
        return health > 0;
    }

    boolean isCollision(float newX, float newY, Tile[][] map) {
        // Determine which tile the new position is in
        int tileX = floor(newX / TILE_SIZE);
        int tileY = floor(newY / TILE_SIZE);

        // Check map bounds
        if (tileX < 0 || tileX >= map.length || tileY < 0 || tileY >= map[0].length) {
            return true; // Treat out-of-bounds as collision
        }

        // Check if the tile is walkable
        return map[tileX][tileY].type != TileType.EMPTY;
    }

     void display() {
        if (!active) return;
        int rowIndex = currentAnim.row;
        int currentFrame = currentAnim.getCurrentFrame();

        int spriteX = currentFrame * spriteWidth;
        int spriteY = rowIndex * spriteHeight;
        pushMatrix();
        translate(x, y);

        boolean flip = false;
        if ((currentState == AnimationState.WALKING || currentState == AnimationState.ATTACKING) 
            && path != null && !path.isEmpty() && path.get(pathIndex).x < x) {
            flip = true;
            scale(-1, 1); 
        }      
       // float drawX = flip ? spriteWidth / 2f : -spriteWidsth / 2f;
        float drawX = -spriteWidth / 2;
        image(spriteSheet, drawX, -spriteHeight + spriteHeight / 4, spriteWidth, spriteHeight,
                spriteX, spriteY, spriteX + spriteWidth, spriteY + spriteHeight); // Source position and size

        popMatrix();

        if (health < maxHealth && currentState != AnimationState.DYING) {
            drawHealthBar();
        }
    }


    void drawHealthBar() {
        float barWidth = TILE_SIZE;
        float healthRatio = (float)health / maxHealth;
        float barHeight = 5;
        fill(255, 0, 0);
        rect(x - barWidth / 2, y - TILE_SIZE / 2 - 10,barWidth * healthRatio, barHeight);
        noFill();
        }
    }

class Node implements Comparable<Node> {
    int x, y;
    float g, f;
    Node parent;

    Node(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override public int compareTo(Node other) {
        return Float.compare(this.f, other.f);
    }
}