import processing.core.PImage;

import java.util.List;
import java.util.Optional;
import java.util.function.BiPredicate;
import java.util.function.Predicate;

public class Princess extends animatable implements Moving, Transforming{

    private int resourceCount;

    private int resourceLimit;

    public Princess(String id, Point position, List<PImage> images, double animationPeriod, double behaviorPeriod) {
        super( id, position, images, animationPeriod, behaviorPeriod) ;
        this.resourceCount= 0;
        this.resourceLimit = 2;
    }

    @Override
    public boolean moveTo(World world, Entity target, EventScheduler scheduler) {
        if (getPosition().adjacentTo(target.getPosition())) {
            if (target instanceof Plant plant) {
                plant.setHealth(plant.getHealth() - 1);
            }
            return true;
        } else {
            Point nextPos = nextPosition(world, target.getPosition());

            if (!getPosition().equals(nextPos)) {
                world.moveEntity(scheduler, this, nextPos);
            }

            return false;
        }
    }

    @Override
    public Point nextPosition(World world, Point destination) {
        PathingStrategy pathingStrategy = new AStarPathingStrategy();

        Predicate<Point> canPassThrough = p -> world.inBounds(p) && (!world.isOccupied(p) || world.getOccupant(p).orElse(null) instanceof Stump);

        BiPredicate<Point, Point> withinReach = Point::adjacentTo;

        List<Point> path = pathingStrategy.computePath(
                getPosition(),
                destination,
                canPassThrough,
                withinReach,
                PathingStrategy.CARDINAL_NEIGHBORS

        );

        if (path.isEmpty()) {
            // Logic if there is no path or at the destination
            return getPosition();
        } else {
            // Logic if there is a path
            return path.get(0);
        }
    }

    @Override
    public void updateImage() {
        setImageIndex(getImageIndex()+1);
    }

    @Override
    public void executeBehavior(World world, ImageLibrary imageLibrary, EventScheduler scheduler) {
        Optional<Entity> target = findPrincessTarget(world);

        if (target.isPresent()) {
            Entity targetEntity = target.get();

            if (moveTo(world, targetEntity, scheduler)) {
                if (targetEntity instanceof House) {
                    transform(world, scheduler, imageLibrary);
                    scheduleBehavior(scheduler, world, imageLibrary);
                }
                else if (targetEntity instanceof Plant plant) {
                    if (plant.getHealth() <= 0) {
                        transform(world, scheduler, imageLibrary);
                    }
                    scheduleBehavior(scheduler, world, imageLibrary);
                }
            } else {
                scheduleBehavior(scheduler, world, imageLibrary);
            }
        } else {
            scheduleBehavior(scheduler, world, imageLibrary);
        }
    }

    public Optional<Entity> findPrincessTarget(World world) {
        List<Class<?>> potentialTargets;

        if (resourceCount == resourceLimit) {
            potentialTargets = List.of(House.class);
        } else {
            potentialTargets = List.of(Tree.class, Sapling.class);
        }

        return world.findNearest(getPosition(), potentialTargets);
    }

    @Override
    public boolean transform(World world, EventScheduler scheduler, ImageLibrary imageLibrary) {
        if (this.resourceCount < this.resourceLimit) {
            this.resourceCount++;
            return true;
        } else {
            this.resourceCount = 0;
            return true;
        }
    }
}
