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;
using Microsoft.Xna.Framework.Input;

class Crops
{
    private int Status;
    private int originalStatus;
    private int cropType = 0;
    private float Timer = 1;
    private int UpdateCrop;
    private float fullTimer = 1;
    private bool housePos = false;
    private Vector2 Size;
    private Random r = new Random();
    private CropTypes DataSet;
    SoilProperties soilProperties = new SoilProperties();
    private float ProductionRate;
    private float tempRain;
    private float prevpred;
    private DayNightCycle Time = new DayNightCycle();
    private int previousDay = 0;
    


    public void updateCrop(Vector2 newSize, DayNightCycle nTime)
    {
        Time = nTime;
        if (UpdateCrop == 60)
        {
            degradeSoil();
            UpdateCrop = 0;
        }

        if (Status == 3 && Timer != 1)
        {
            Timer = Timer - 1f * ProductionRate;
        }
        Size = newSize;
        UpdateCrop++;

        if (Timer < 1)
        {
            Timer = 1;
        }
    }

    public void updateProductionRate()
    {
        getProductionRate(DataSet);
    }

    public float getSpeedFactor(float tractorSpeed)
    {
        if (getCostOnMovement() == 1)
            return (1f * tractorSpeed);
        return (1f * tractorSpeed) / (getCostOnMovement() / 5.0f);
    }

    public SoilProperties getSoilProperties()
    {
        return soilProperties;
    }

    public void Fertilize(Fertilizer fertilizer)
    {
        soilProperties.Nitrogen += fertilizer.Nitrogen;
        soilProperties.Phosphorous += fertilizer.Phosphorus;
        soilProperties.Potassium += fertilizer.Potassium;
        
        if (soilProperties.Nitrogen > 42)
            soilProperties.Nitrogen = 42;
        if (soilProperties.Phosphorous > 42)
            soilProperties.Phosphorous = 42;
        if (soilProperties.Potassium > 19)
            soilProperties.Potassium = 19;
            
    }

    public bool isSaturated()
    {
        if (soilProperties.Nitrogen > 40 && (soilProperties.Phosphorous > 40 || soilProperties.Potassium > 17))
            return true;
        if (soilProperties.Phosphorous > 40 && soilProperties.Potassium > 17)
            return true;
        return false;
    }

    public bool isSaturated(int threshold)
    {
        if (soilProperties.Nitrogen > 40 - threshold && (soilProperties.Phosphorous > 40 - threshold || soilProperties.Potassium > 17 - (threshold * 17/40)))
            return true;
        if (soilProperties.Phosphorous > 40 - threshold && soilProperties.Potassium > 17 - (threshold *17/40))
            return true;
        return false;
    }

    public float getCropTimer()
    {
        return Timer;
    }

    public int getCropTimerBar(int tileSize)
    {

        int x = (int)((1 - ((float)Timer / fullTimer)) * (tileSize - tileSize / 3));
        return x;
    }

    public void init()
    {
        soilProperties.setSoilProperties();
    }

    // Changes the time required for the crops to be harvestable
    public void setCropTimer()
    {
        if (cropType == 1)          // Barley
        {
            Timer = 300;
            fullTimer = Timer;
        }
        else if (cropType == 1)     // Wheat
        {
            Timer = 600;
            fullTimer = Timer;
        }
        else if (cropType == 2)     // Berries
        {
            Timer = 1200;
            fullTimer = Timer;
        }
        else                        // Fruit Trees
        {
            Timer = 2400;
            fullTimer = Timer;
        }
    }

    public int getCostOnMovement()
    {
        if (Status == 1)        //grass
        {
            return 1;
        }
        else if (Status == 2)   //dirt
        {
            return 8;
        }
        else
        {
            if (cropType == 0)
            {
                return 16;          //Barley
            }
            if (cropType == 1)
            {
                return 16;          //Barley
            }
            else if (cropType == 2)
            {
                return 16;          //Cotton
            }
            else if (cropType == 3)
            {
                return 16;          //Ground Nuts
            }
            else if (cropType == 4)
            {
                return 16;          //Maize
            }
            else if (cropType == 5)
            {
                return 16;          //Millets
            }
            else if (cropType == 6)
            {
                return 16;          //Oil Seeds
            }
            else if (cropType == 7)
            {
                return 16;          //Paddy
            }
            else if (cropType == 8)
            {
                return 16;          //Pulses
            }
            else if (cropType == 9)
            {
                return 16;          //Sugarcane
            }
            else if (cropType == 10)
            {
                return 16;          //Wheat
            }
            else
            {
                return 16;          //Tobacco
            }
        }
    }

    public void degradeSoil()
    {
        Random r = new Random();
        if (soilProperties.Nitrogen > 4.0f)
        {
            soilProperties.Nitrogen = soilProperties.Nitrogen - ((soilProperties.NitrogenDegradeRate * (float)Math.Pow(ProductionRate, 2)) * (float)Math.Pow((r.NextDouble() + 0.5f), 2));
        }
        if (soilProperties.Phosphorous > 0.1f)
        {
            soilProperties.Phosphorous = soilProperties.Phosphorous - ((soilProperties.PhosphorousDegradeRate * (float)Math.Pow(ProductionRate, 2)) * (float)Math.Pow((r.NextDouble() + 0.5f), 2));
        }
        if (soilProperties.Potassium > 0.1f)
        {
            soilProperties.Potassium = soilProperties.Potassium - ((soilProperties.PotassiumDegradeRate * (float)Math.Pow(ProductionRate, 2)) * (float)Math.Pow((r.NextDouble() + 0.5f), 2));
        }
    }

    public void updateRainfall(float Rain)
    {
        if (Rain >= 0.45f)
        {
            soilProperties.Rainfall = soilProperties.Rainfall + Rain * 4;
        }
    }

    public void setPrevRainfall()
    {

        soilProperties.prevRainfall = soilProperties.Rainfall;
        if (soilProperties.prevRainfall > 3616)
            soilProperties.prevRainfall = 3616;
        else if (soilProperties.prevRainfall < 236)
            soilProperties.prevRainfall = 236;
        soilProperties.Rainfall = 0;

    }


    public void setCropType(int Type, CropTypes nCropType)
    {
        if (Timer == fullTimer)
        {
            CropTypes temp = DataSet;
            DataSet = nCropType;
            cropType = Type;
            if (Status > 1)
            {
                soilProperties.Area = r.Next(nCropType.AreaMin, nCropType.AreaMax);
                if (temp != nCropType)
                    updateMLModel(DataSet, 1.0f);
            }
        }

    }

    public int getStatus()
    {
        if (Status != 3)
        {
            return Status;
        }
        else
        {
            return Status; // + cropType; When unique crop textures have been added
        }
    }

    public int getCropType()
    {
        return cropType;
    }

    public void setStatus(int newStatus)
    {
        Status = newStatus;
        Timer = getCropTimer();
    }

    public void setOriginalStatus()
    {
        originalStatus = Status;
    }


    public void setHousePos(bool state)
    {
        housePos = state;
        if (state)
        {
            Timer = 1;
            Status = 1;
        }
        else
        {
            Status = originalStatus;
        }
    }

    public bool getHousePos()
    {
        return housePos;
    }

    public bool belowCapacity()
    {
        return ((int)(soilProperties.Nitrogen + soilProperties.Potassium + soilProperties.Phosphorous)) < soilProperties.Capacity;
    }

    public Vector4 getColour()
    {
        float r, g, b, a;
        float productionRate, overhead;

        if (ProductionRate > 1.0f)
        {
            productionRate = 1.0f;
            overhead = ProductionRate - 1.0f;
        }
        else
        {
            productionRate = ProductionRate;
            overhead = 0.0f;
        }

        r = (1.0f - productionRate) * 4;
        g = 0.0f + productionRate;
        b = 0.0f + overhead * 3;
        a = 255;

        return new Vector4(r, g, b, a);
    }

    public float getProductionRate(CropTypes Sample)
    {
        float predProd = 1.0f;
        if (Status > 1 && Time.getDays() != previousDay)
        {
            predProd = updateMLModel(Sample, predProd);
        }
        prevpred = predProd;
        ProductionRate = 1;
        float min = 1.0f;
        if (DataSet != null)
        {
            //ProductionRate = ProductionRate + (ProductionRate * compareToDatset(soilProperties.Temperature, Sample.Temparature));
            //ProductionRate = ProductionRate + (ProductionRate * compareToDatset(soilProperties.Moisture, Sample.Moisture));
            //ProductionRate = ProductionRate + (ProductionRate * compareToDatset(soilProperties.Humidity, Sample.Humidity));
            if (DataSet.soilType[0] != null)
            {
                if (Sample.soilType[0] == soilProperties.soilType)
                {
                    ProductionRate = ProductionRate + 0.1f;
                }
                if (DataSet.soilType[1] != null)
                {
                    if (Sample.soilType[1] == soilProperties.soilType)
                    {
                        ProductionRate = ProductionRate + 0.08f;
                    }
                    if (DataSet.soilType[2] != null)
                    {
                        if (Sample.soilType[2] == soilProperties.soilType)
                        {
                            ProductionRate = ProductionRate + 0.5f;
                        }

                    }
                }
            }
            min = Math.Min(compareToDatset(soilProperties.Phosphorous, Sample.Phosphorous), Math.Min(compareToDatset(soilProperties.Potassium, Sample.Potassium), compareToDatset(soilProperties.Nitrogen, Sample.Nitrogen)));
            ProductionRate = ProductionRate + (ProductionRate * min);
            if (ProductionRate < 0)
            {
                ProductionRate = 0;
            }
            ProductionRate = ProductionRate / 1.5f;
        }
        ProductionRate = (float)Math.Pow(ProductionRate, 2.5f);
        return ProductionRate * prevpred;
    }

    public float updateMLModel(CropTypes Sample, float predProd)
    {
        previousDay = Time.getDays();
        bool correctSeason = false;
        foreach (string i in Sample.Season)
        {
            if (i == Time.getTimeOfYear() || i == "Whole Year")
            {
                correctSeason = true;
                break;
            }
        }

        if (correctSeason)
        {
            predProd = Game1.Sources.ML_Joel.Engine.PredictProductionwithRainfall(soilProperties, Time);
            predProd = (predProd / soilProperties.Area) / 2;
        }
        else
            predProd = 0.20f;

        return predProd;
    }

    public float getProductionRate()
    {
        return ProductionRate;
    }

    public float compareToDatset(float i, float j)
    {
        if (i < j)
        {
            return (i / j);
        }
        else
        {
            return (j / i);
        }

        
    }


    public void Inspect(int tileSize, int Spacing, SpriteFont Bold, SpriteBatch spriteBatch, string[] cropTypesNames)
    {
        spriteBatch.Begin();
        if (housePos)
        {
            spriteBatch.DrawString(Bold, "Tiletype: House", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.Teal);
        }
        else if (Status == 0)
        {
            spriteBatch.DrawString(Bold, "Tiletype: Boulders", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.Teal);
        }
        else if (Status == 1)
        {
            spriteBatch.DrawString(Bold, "Tiletype: Grassfield", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.Teal);
        }
        else if (Status == 2)
        {
            spriteBatch.DrawString(Bold, "Tiletype: Soil", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.Teal);
        } 
        else if (Status == 3)
        {
            int x = (int)(((float)Timer / fullTimer) * 100);
            x = 100 - x;
            spriteBatch.DrawString(Bold, "Tiletype: Crop ", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.Teal);
            spriteBatch.DrawString(Bold, "Completion: " + x + "%", new Vector2(240, Size.Y * (tileSize + Spacing) + 82), Color.Teal);
        }
        if (Status != 3)
        {
            spriteBatch.DrawString(Bold, "-------------", new Vector2(240, Size.Y * (tileSize + Spacing) + 82), Color.DarkRed);
        }
        if (Status > 1)
        {
            spriteBatch.DrawString(Bold, "Prefered Crop: " + cropTypesNames[cropType], new Vector2(240, Size.Y * (tileSize + Spacing) + 62), Color.Teal);
        }
        else
        {
            spriteBatch.DrawString(Bold, "None", new Vector2(240, Size.Y * (tileSize + Spacing) + 62), Color.Teal);
        }
        spriteBatch.DrawString(Bold, "Soil Properties:", new Vector2(240, Size.Y * (tileSize + Spacing) + 122), Color.DarkRed);
        spriteBatch.DrawString(Bold, "Soil Type: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 142), Color.DarkRed);
        spriteBatch.DrawString(Bold, soilProperties.soilType, new Vector2(370, Size.Y * (tileSize + Spacing) + 142), Color.Teal);
        spriteBatch.DrawString(Bold, "Temparature: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 162), Color.DarkRed);
        spriteBatch.DrawString(Bold, soilProperties.Temperature.ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 162), Color.Teal);
        spriteBatch.DrawString(Bold, "Moisture: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 182), Color.DarkRed);
        spriteBatch.DrawString(Bold, soilProperties.Moisture.ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 182), Color.Teal);
        spriteBatch.DrawString(Bold, "Humidity: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 202), Color.DarkRed);
        spriteBatch.DrawString(Bold, soilProperties.Humidity.ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 202), Color.Teal);
        spriteBatch.DrawString(Bold, "Phosphorous: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 222), Color.DarkRed);
        spriteBatch.DrawString(Bold, Math.Round(soilProperties.Phosphorous,1).ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 222), Color.Teal);
        spriteBatch.DrawString(Bold, "Potassium: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 242), Color.DarkRed);
        spriteBatch.DrawString(Bold, Math.Round(soilProperties.Potassium, 1).ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 242), Color.Teal);
        spriteBatch.DrawString(Bold, "Nitrogen: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 262), Color.DarkRed);
        spriteBatch.DrawString(Bold, Math.Round(soilProperties.Nitrogen, 1).ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 262), Color.Teal);
        spriteBatch.DrawString(Bold, "Production Rate: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 282), Color.DarkRed);
        spriteBatch.DrawString(Bold, Math.Round((ProductionRate * 100), 1).ToString() + "%", new Vector2(370, Size.Y * (tileSize + Spacing) + 282), Color.Teal);
        spriteBatch.DrawString(Bold, "Last Years Rainfall: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 302), Color.DarkRed);
        spriteBatch.DrawString(Bold, Math.Round((soilProperties.prevRainfall), 1).ToString() + "mm", new Vector2(370, Size.Y * (tileSize + Spacing) + 302), Color.Teal);
        spriteBatch.DrawString(Bold, "Rainfall: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 322), Color.DarkRed);
        spriteBatch.DrawString(Bold, Math.Round((soilProperties.Rainfall), 1).ToString() + "mm", new Vector2(370, Size.Y * (tileSize + Spacing) + 322), Color.Teal);
        spriteBatch.DrawString(Bold, "Rain mm/s: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 342), Color.DarkRed);
        spriteBatch.DrawString(Bold, Math.Round((tempRain * 2), 2).ToString() + "mm", new Vector2(370, Size.Y * (tileSize + Spacing) + 342), Color.Teal);
        spriteBatch.DrawString(Bold, "Area: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 362), Color.DarkRed);
        spriteBatch.DrawString(Bold, soilProperties.Area + "m^2", new Vector2(370, Size.Y * (tileSize + Spacing) + 362), Color.Teal);
        spriteBatch.End();
    }
}