using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using Jypeli;
using Jypeli.Assets;
using Jypeli.Controls;
using Jypeli.Widgets;

namespace matopeli;

/// @author Omanimi
/// @version 30.10.2023
/// <summary>
/// 
/// </summary>
public class matopeli : PhysicsGame
{
    private static readonly string[] tasonkuva = {
        "#####################",
        "#                   #",
        "#                   #",
        "#                   #",
        "#                   #",
        "#                   #",
        "#                   #",
        "#                   #",
        "#                   #",
        "#                   #",
        "#                   #", 
        "#                   #",
        "#                   #",
        "#                   #",
        "#                   #",
        "#                   #",
        "#                   #",
        "#####################",
    };
    private Objektit Mato;
    private Objektit Omena;
    private Objektit MatoMuu;
    
    public List<Vector> MatoSijainti = new List<Vector>();
    public List<PhysicsObject> MatoKeho = new List<PhysicsObject>();

    public int leveys = 30;
    public int korkeus = 30;
    
    private static readonly Image seinakuva = LoadImage("seina.png");
    private static readonly Image matopaakuva = LoadImage("matopaa.png");
    private readonly Image matokehokuva = LoadImage("matokeho.png");
    private readonly Image omenakuva = LoadImage("omena.png");
    private readonly Image kenttatausta = LoadImage("kenttatausta.png");
    
    private bool SuuntaYlos = false;
    private bool SuuntaAlas = false;
    private bool SuuntaOikea = false;
    private bool SuuntaVasen = false;

    private bool MatoLiikkunut = true;

    private bool OmenaKentalla = true;
    public override void Begin()
    {
        // Kirjoita ohjelmakoodisi tähän

        PhoneBackButton.Listen(ConfirmExit, "Lopeta peli");
        Keyboard.Listen(Key.Escape, ButtonState.Pressed, ConfirmExit, "Lopeta peli");
        AloitaUusiPeli();
        
    }

    public void AloitaUusiPeli()
    {
        Level.CreateBorders(0.0,true,Color.Green);
        ClearAll();
        SuuntaAlas = true;
        LuoMato();
        Asetaohjaimet();
        LuoAikalaskuri();
        LuoOmena();
        
        TileMap tiles = TileMap.FromStringArray(tasonkuva);
        tiles['#'] = LuoSeina;
        tiles.Insert(leveys,korkeus);
    }
    private void Asetaohjaimet()
    {
        Keyboard.Listen(Key.Up, ButtonState.Pressed, VaihdaSuuntaYlos, "Turn upwards");
        Keyboard.Listen(Key.Down, ButtonState.Pressed, VaihdaSuuntaAlas, "Turn downwards");
        Keyboard.Listen(Key.Left, ButtonState.Pressed, VaihdaSuuntaVasen , "Turn left");
        Keyboard.Listen(Key.Right, ButtonState.Pressed, VaihdaSuuntaOikea, "Turn right");
    }
    private PhysicsObject LuoMato()
    {
        Mato = new Objektit(leveys, korkeus);
        Mato.Image = matopaakuva;
        Add(Mato);
        Mato.Tag = "mato";
        AddCollisionHandler(Mato, "omena", delegate(IPhysicsObject Mato, IPhysicsObject Omena) {MatoSyoOmenan();  });
        return Mato;
    }

    /// <summary>
    /// Luodaan omena johonkin satunnaiseen kohtaan kartalla, joka ei ole samassa kohtaa madon kanssa.
    /// </summary>
    /// <returns></returns>
    private PhysicsObject LuoOmena()
    {
        
        Vector paikka = Level.GetRandomPosition();

        for (int i = 0; i < 100; i++)
        {
            if (paikka.X-Mato.X<5)
            {
                paikka = Level.GetRandomPosition();
            }
            if (paikka.X-Mato.Y<5)
            {
                paikka= Level.GetRandomPosition();
            }
            if (paikka.X<30)
            {
                if (paikka.X < -30)
                {
                    paikka = Level.GetRandomPosition();
                }
            }
            if (paikka.Y<30)
            {
                if (paikka.Y<-30)
                {
                    paikka = Level.GetRandomPosition();
                } 
            }
            else
            {
                break;
            }
        }
        
        Omena = new Objektit(korkeus, leveys);
        Omena.Shape = Shape.Circle;
        Omena.Position = paikka;
        Omena.Image = omenakuva;
        Omena.Tag = "omena";
        Add(Omena);
        OmenaKentalla = true;
        return Omena;
    }
    private PhysicsObject LuoSeina()
    {
        PhysicsObject Seina = PhysicsObject.CreateStaticObject(leveys, korkeus);
        Seina.Color = Color.Green;
        Seina.Image = seinakuva;
        Seina.Tag = "seina";
        return Seina;
    }
    
    /// <summary>
    /// Tehdään aliohjelma, joka luo uusia osia madon perään.
    /// </summary>
    public PhysicsObject LuoMatoKeho()
    {
        MatoMuu = new Objektit(leveys-8, korkeus-8);
        MatoMuu.Tag = "matokeho";
        MatoMuu.Image = matokehokuva;
        Vector Paikka = MatoSijainti[MatoSijainti.Count - 1 - MatoKeho.Count];
        MatoMuu.IgnoresCollisionResponse = true;
        MatoMuu.Position = Paikka;
        Add(MatoMuu);
        MatoKeho.Add(MatoMuu);
       
        

        return MatoMuu;
    }
    
    private void MatoSyoOmenan()
    {
        Omena.Destroy();
        OmenaKentalla = false;
    }
    
     private void VaihdaSuuntaYlos()
        {
            
            if (SuuntaAlas==true)
            {
                SuuntaOikea = false;
                SuuntaVasen = false;
                SuuntaYlos = false;
                SuuntaAlas = true;
            }
            else
            {
                SuuntaOikea = false;
                SuuntaVasen = false;
                SuuntaYlos = true;
                SuuntaAlas = false;
            }
        }
     
     private void VaihdaSuuntaAlas()
        {
            if (SuuntaYlos==true)
            {
                SuuntaOikea = false;
                SuuntaVasen = false;
                SuuntaYlos = true;
                SuuntaAlas = false;
            }
            else
            {
                SuuntaOikea = false;
                SuuntaVasen = false;
                SuuntaYlos = false;
                SuuntaAlas = true;
            }
        }
        
     private void VaihdaSuuntaOikea()
        {
            if (SuuntaVasen == true)
            {
                
                SuuntaOikea = false;
                SuuntaVasen = true;
                SuuntaYlos = false;
                SuuntaAlas = false;
            }
            else
            {
                SuuntaOikea = true;
                SuuntaVasen = false;
                SuuntaYlos = false;
                SuuntaAlas = false;
            }

        }
        
     private void VaihdaSuuntaVasen()
        {
            if (SuuntaOikea==true)
            {
                SuuntaOikea = true;
                SuuntaVasen = false;
                SuuntaYlos = false;
                SuuntaAlas = false;
            }
            else
            {
                SuuntaOikea = false;
                SuuntaVasen = true;
                SuuntaYlos = false;
                SuuntaAlas = false;
            }
        }
     private void LuoAikalaskuri()
        {
            Timer aikalaskuri = new Timer();
            aikalaskuri.Interval = 0.1;
            aikalaskuri.Timeout += PaivitaKentta;
            aikalaskuri.Start();
        }

     /// <summary>
     /// Kun ajastimesta loppuu aika, siirtyy peli tähän funktioon, jonka tarkoituksena on hahmottaa, mitä kaikkea pelissä on tapahtunut ja miten siihen tulee reagoida.
     /// 
     /// </summary>
     private void PaivitaKentta()
     {
         if (MatoLiikkunut == false)
         {
             return;
         }
         if (OmenaKentalla == false)
         {
             LuoMatoKeho();
             LuoOmena();
         }

         MatoSijainti.Add(new Vector(Mato.X,Mato.Y));
         LiikutaMatoa();
         LiikutaKehoa();
         MatoSijainti.Add(new Vector(Mato.X,Mato.Y));    

     }

    private void LiikutaMatoa()
    {
        if (SuuntaYlos==true)
        {
            Mato.Y = Mato.Y + leveys;
            Mato.Angle = Angle.FromDegrees(90);
        }
        if (SuuntaAlas==true)
        {
            Mato.Y= Mato.Y - leveys;
            Mato.Angle = Angle.FromDegrees(270);
        }
        if (SuuntaOikea==true)
        {
            Mato.X= Mato.X + leveys;
            Mato.Angle = Angle.FromDegrees(0);
           
        }
        if (SuuntaVasen==true)
        {
            Mato.X= Mato.X - leveys;
            Mato.Angle = Angle.FromDegrees(180);
            
        }
    }

    /// <summary>
    /// Tehdään silmukka, joka käy madon kaikki sijainnit ja liikuttaa madon muut osat niiden mukaan.
    /// </summary>

    private void LiikutaKehoa()
    {
        if (MatoKeho.Count==0)
        {
            return;
        }
        MatoLiikkunut = false;
        MatoKeho[0].X = MatoSijainti[MatoSijainti.Count - 1].X;
        MatoKeho[0].Y = MatoSijainti[MatoSijainti.Count - 1].Y;
        
        for (int i = 1; i < MatoKeho.Count; i++)
        {
            MatoKeho[i].X = MatoSijainti[MatoSijainti.Count - 2*i].X;
            MatoKeho[i].Y = MatoSijainti[MatoSijainti.Count - 2*i].Y;
        }

        MatoLiikkunut = true;
    }


    public class Objektit : PhysicsObject
    {
         public Objektit(double leveys, double korkeus)
        : base(leveys, korkeus)
        {
            Mass = 0;
            IsUpdated = true;
        }
    }



}