using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;


class AI
{
    private Vector2 tractorPos;
    private Vector2 housePos;
    private Farm farm;
    private Vector2 Size;
    private Vector2 targetPos;
    private Inventory inventory = new Inventory();
    private FertilizerHolder fertilizerHolder = new FertilizerHolder();
    private int Rotation;
    private Astar astar = new Astar();
    public bool WaitTwoFrames { get; set; }

    private Random r = new Random();


    public void init()
    {
        inventory.initInventorySystem();
    }


    public void update(Farm newFarm, Vector2 newSize, Vector2 newTractorPos, Vector2 newHousePos, Vector2 newtargetPos, int rotation)
    {
        tractorPos = new Vector2((int)newTractorPos.X, (int)newTractorPos.Y);
        housePos = new Vector2((int)newHousePos.X, (int)newHousePos.Y);
        targetPos = newtargetPos;
        farm = newFarm;
        Size = newSize;
        Rotation = rotation;
        astar.update(farm.getCrops(), Size, tractorPos, housePos, rotation);
    }


    public void drawInventory(Input input, SpriteBatch spriteBatch, SpriteFont Bold, Cargo itemStorageDefined)
    {
        inventory.printItems(input, spriteBatch, Bold);
    }

    public Path newTarget()
    {
        PriorityQueueC5 queue = new PriorityQueueC5();
        int score = 0;
        int count = 0;
        int testsize = 2;
        Path newTarget;
        Nodes nodes;
        Random random = new Random();

        if (astar.GetAdjacentNodes(tractorPos).Count == 0)
            nodes = new Nodes(housePos);
        else
        {
            List<Nodes> templist = astar.GetAdjacentNodes(tractorPos);
            nodes = templist[random.Next(0, templist.Count())];
            templist.Clear();
        }

        if (tractorPos != housePos)
            if (inventory.getWeight() == inventory.getMaxWeight() || inventory.isMissingFertilizer())
            {
                astar.update(farm.getCrops(), Size, tractorPos, housePos, housePos, Rotation);
                return astar.FindPath(true);
            }
        while (true)
        {
            for (int x = 0; x < Size.X; x++)
                for (int y = 0; y < Size.Y; y++)
                {
                    if (farm.getCrop(x, y).getStatus() >= 2 && tractorPos != new Vector2(x, y))
                    {
                        if (farm.getCrop(x, y).getStatus() != 2 && (farm.getCrop(x, y).getProductionRate() > 0.99f || !farm.getCrop(x, y).belowCapacity()))
                        {
                            //skip growing fields with high production rate
                        }
                        else
                        {
                            score = calculateSoilScore(x, y);
                            queue.AddToQueue(x, y, score);
                            if (farm.getCrop(x, y).getCropTimer() == 1 || farm.getCrop(x, y).getStatus() == 2)
                                count++;
                        }
                    }
                }
                break;
        }

        if (queue.getCount() == 0)
        {
            astar.update(farm.getCrops(), Size, tractorPos, housePos, nodes.getCords(), Rotation);
            return newTarget = astar.FindPath(true);
        }
        
        newTarget = GetMinFNode(Math.Min(testsize, queue.getCount()), queue);
        queue = null;

        return newTarget;
    }

    public Farm changeCropStatus()
    {
        int x = (int)tractorPos.X;
        int y = (int)tractorPos.Y;
        Fertilizer fertilizer = new Fertilizer();
        fertilizerHolder.init();
        WaitTwoFrames = false;
        if (farm.getCrop(x, y).getStatus() >= 2)
        {
            fertilizer = fertilizerHolder.GetFertilizer(Engine.PredictFertilizer(farm.getCrop(x, y), farm.getPresetCropTypes(farm.getCrop(x, y).getCropType())));
            while (!(farm.getCrop(x, y).isSaturated(-1)) && farm.getCrop(x, y).belowCapacity() && inventory.useItem(fertilizerHolder.GetFertilizerID(fertilizer.Name), 0, false))
            {
                farm.getCrop(x, y).Fertilize(fertilizer);
                fertilizer = fertilizerHolder.GetFertilizer(Engine.PredictFertilizer(farm.getCrop(x, y), farm.getPresetCropTypes(farm.getCrop(x, y).getCropType())));
                WaitTwoFrames = true;
            }
        }
        if (farm.getCrop(x, y).getCropTimer() == 1)
        {
            farm.setCropStatus(tractorPos.X, tractorPos.Y);
            if (farm.getCrop(x, y).getStatus() == 2)
            {
                inventory.addItem(farm.getCrop(x, y).getCropType() - 1, 1);
            }
            
        }
        return farm;
    }

    public Inventory getInventory()
    {
        return inventory;
    }

    private int calculateSoilScore(int x, int y)
    {
        int score = 1;
        int statusScore = 1;
        int timerScore = 1;
        int saturationScore = 1;
        int productionRateScore = 1;
        int aproxDistance = (int)(Math.Abs(x - tractorPos.X) + Math.Abs(y - tractorPos.Y));

        Crops crop = farm.getCrop(x, y);
        int cropType = crop.getCropType();

        if (crop.getCropTimer() == 1)
            timerScore = 100;

        productionRateScore = (int)(crop.getProductionRate() * 25);
        score = (int)(crop.getProductionRate() * -50);

        if (crop.getStatus() == 2)
        {
            statusScore = 50;
            productionRateScore = 0;
        }
        else if (crop.getStatus() == 3)
            statusScore = -100;

        if (!crop.isSaturated(2))
            saturationScore = 5;
        else
        {
            saturationScore = -100;
        }

        return score + (-aproxDistance * 10) + statusScore + timerScore + saturationScore;
    }

    private float norm(float min, float max, float val)
    {
        return ((val - min) / (max - min));
    }

    public Path GetMinFNode(int testSize, PriorityQueueC5 queue)
    {
        int index = 0;
        int min = 9999;
        Path path = new Path();
        List<PQEntry> entryList = new List<PQEntry>();
        Path[] pathList = new Path[testSize];
        for (int i = 0; i < testSize; i++)
        {
            entryList.Add(queue.DeleteMax());
        }

        for (int i = 0; i < testSize; i++)
        {
            Nodes temp = new Nodes(entryList[i].Coordinates);
            astar.update(farm.getCrops(), Size, tractorPos, housePos, temp.getCords(), Rotation);
            path = astar.FindPath(false);
            pathList[i] = path;
            Nodes tempF = new Nodes(path.getByIndex(0));
            if (min > tempF.getF())
            {
                min = tempF.getF();
                index = i;
            }
        }

        return pathList[index].FlipArray();
    }

    public Path GetMaxFNode(int testSize, PriorityQueueC5 queue)
    {
        int index = 0;
        int max = -9999;
        Path path = new Path();
        List<PQEntry> entryList = new List<PQEntry>();
        Path[] pathList = new Path[testSize];
        for (int i = 0; i < testSize; i++)
        {
            entryList.Add(queue.DeleteMax());
        }

        for (int i = 0; i < testSize; i++)
        {
            Nodes temp = new Nodes(entryList[i].Coordinates);
            astar.update(farm.getCrops(), Size, tractorPos, housePos, temp.getCords(), Rotation);
            path = astar.FindPath(false);
            pathList[i] = path;
            Nodes tempF = new Nodes(path.getByIndex(0));
            if (max < tempF.getF())
            {
                max = tempF.getF();
                index = i;
            }
        }

        return pathList[index].FlipArray();
    }


    public void reloadCargo()
    {
        inventory.clearInventory();
        inventory.fillWithFertilizer();

    }



}