using System;
using System.Collections.Generic;
using Jypeli;
using Jypeli.Widgets;
using Color = Jypeli.Color;

namespace KelaCombatTesti;

/// @author Sakari Hanki ja Salla Laine
/// @version 28.03.2025
/// <summary>
/// Pelissä tikkuhenkilö hakkaa kelabotteja pesismailalla
/// </summary>
    public class KelaCombatTesti : PhysicsGame
    {
        private int _kenttanumero = 0; 
        private string[] _kentat = {"kentta1", "kentta2"};
       private Image[] _henkiloSaapastelu = LoadImages("kavely1", "kavely2");
       private Image[] _paikallaanAnimaatio = LoadImages("kavely1");
       private Image[] _putoamisAnimaatio = LoadImages("putoaminen1", "putoaminen2", "putoaminen3", "putoaminen4", "putoaminen5");
       private Image[] _kelabottiKavely = LoadImages("Kelabotti", "Kelabotti2");
        
       private SoundEffect _hyppyaani = LoadSoundEffect("Hyppyaani");
       private SoundEffect _viinapulloaani = LoadSoundEffect("Viinapulloaani");
       private SoundEffect _keladamageaani = LoadSoundEffect("Keladamageaani");
       private SoundEffect _kavelyaani = LoadSoundEffect("Kavelyaani");
       private SoundEffect _lyontiaani = LoadSoundEffect("Lyontiaani");
       private Timer _ajastin = new Timer();

       private PlatformCharacter _pelaaja;
       private PhysicsObject _pesismaila;
       private PhysicsObject _viinapullo;
       private PhysicsObject _kappale;
       private PhysicsObject _exit;
       private PhysicsObject _ansa;
       private PlatformCharacter _kelabotti;
       
       private Image _tiiliseinakuva = LoadImage("tiiliseina");
       private Image _kelabottikuva = LoadImage("Kelabotti");
       private Image _viinapullokuva = LoadImage("Viinapullo.png");
       private Image _uloskaynti = LoadImage("Uloskaynti");
       private Image _ansakuva = LoadImage("Tyohakemuskasa");
        
        private List<PhysicsObject> _spawnipaikat = new List<PhysicsObject>(); // tässä listataan mahdolliset paikat, johon kelabotti voi spawnaa. Lista pitää sisällään spawnereita.
        
        //IntMeter edustaa muuttujia, jotka voivat kasvaa tai vähentyä tietyllä tavalla 
        private IntMeter _pisteet;  //pelaajan keräämät pisteet 
        private DoubleMeter _pelaajanElamaaskuri; //pelaajan elämät
        
        //Label = tekstielementti, joka näytetään pelissä 
        private Label _pisteNaytto; //pisteiden näyttäminen ruudulla 

        
        /// <summary>
        /// Peli alkaa tästä
        /// </summary>
        public override void Begin()
        {
            LuoKentta(0);
        }
        
        
        /// <summary>
        /// Vasemmalle kävely
        /// </summary>
        /// <param name="vektori">suuntavektori</param>
        private void LiikuVasemmalle(Vector vektori)
        {
            _pelaaja.Walk(-120);
        }

        
        /// <summary>
        /// Vasemmalle kävedllessä kuuluva ääni
        /// </summary>
        /// <param name="vektori">suuntavektori</param>
        private void AaniVasemmalle(Vector vektori)
        {
            _kavelyaani.Play();
            _ajastin.Interval = 0.5; // Äänen kesto
            _ajastin.Timeout += delegate { _kavelyaani.Play(); };
            _ajastin.Start();
        }

        
        /// <summary>
        /// Vasemmalle suuntautuvan äänen lopettaminen
        /// </summary>
        /// <param name="vektori">suuntavektori</param>
        private void LopetaAaniVasemmalle(Vector vektori)
        {
            if (_ajastin != null) // Tarkistetaan, onko ajastin luotu
            {
                _ajastin.Stop(); // Pysäytetään ajastin
                _kavelyaani.Stop(); // Lopetetaan äänen toisto
            }
        }
        
        
        /// <summary>
        /// Oikealle kävely
        /// </summary>
        /// <param name="vektori">suuntavektori</param>
        private void LiikuOikealle(Vector vektori)
        {
            _pelaaja.Walk(120);
        }
        
        
        /// <summary>
        /// Ääni oikealle liikkuessa
        /// </summary>
        /// <param name="vektori">suuntavektori</param>
        private void AaniOikealle(Vector vektori)
        {
            _kavelyaani.Play();
            _ajastin.Interval = 0.5; // Äänen kesto
            _ajastin.Timeout += delegate { _kavelyaani.Play(); };
            _ajastin.Start();
        }

        
        /// <summary>
        /// Oikealle suuntautuvan äänen lopettaminen
        /// </summary>
        /// <param name="vektori">suuntavektori</param>
        private void LopetaAaniOikealle(Vector vektori)
        {
            if (_ajastin != null) // Tarkistetaan, onko ajastin luotu
            {
                _ajastin.Stop(); // Pysäytetään ajastin
                _kavelyaani.Stop(); // Lopetetaan äänen toisto
            }
        }
        
        
        /// <summary>
        /// Hyppääminen
        /// </summary>
        /// <param name="vektori">suuntavektori</param>
        private void Hyppaa(Vector vektori)
        {
            _hyppyaani.Play();
            _pelaaja.Jump(900.0);
        }
        
        
        /// <summary>
        /// Tässä luodaan pelikenttä
        /// </summary>
        private void LuoKentta(int numero)
        {
            if (_kenttanumero == _kentat.Length)
            {
                Label valmistuminen = new Label(800, 60, "Toimeentulohakemus hyväkystty.");
                valmistuminen.Y = 140;
                valmistuminen.Font = new Font(60);
                valmistuminen.TextColor = Color.LimeGreen;
                Add(valmistuminen);
                
            }
            else 
            {
                ClearAll();
                for (int i = 0; i < 20; i++)
                {
                    GameObject koriste = TeeKoriste(Level.BoundingRect);
                    Add(koriste);
                }
            
                Level.Background.CreateGradient(Color.DarkGray, Color.Blue);
                Gravity = new Vector(0, -1100.0);
           
                // pelissä kentät luodaan piirtämällä pikseleitä. Pikselin väri kuvaa aina jotain tiettyä asiaa kentällä
                // ruutu = pikseli
                ColorTileMap ruudut = ColorTileMap.FromLevelAsset(_kentat[numero]);
            
                ruudut.SetTileMethod(Color.Lime, LuoPelaaja); //LIME pikseli on pelaaja,  0, 255, 0
                ruudut.SetTileMethod(Color.Black, LuoTaso); //MUSTA on tiiliseinää
                ruudut.SetTileMethod(Color.Red, LuoKelabottiSpawni); //PUNAISEEN voi spawnaa vihu
                ruudut.SetTileMethod(Color.SkyBlue, LuoViinapullo); //VAALEANSNISET on pelaajaa parantavia viinapulloja 135, 206, 235
                ruudut.SetTileMethod(Color.Wheat, LuoExit); //  245, 222, 179
                ruudut.SetTileMethod(Color.Lavender, LuoAnsa); // 220 208 255
            
                ruudut.Execute(80, 80);
                Timer.CreateAndStart(5.0, LuoKelabotti);
            
                LuoElamalaskuri();
                LuoPistelaskuri();
            
                Camera.Follow(_pelaaja);
                LisaaOhjaimet();
            }
        }

        
        /// <summary>
        /// Aliohjelmassa lisätään ohjaimet
        /// </summary>
        private void LisaaOhjaimet()
        {
            Keyboard.Listen(Key.A, ButtonState.Pressed, AaniVasemmalle, null, new Vector());
            Keyboard.Listen(Key.D, ButtonState.Pressed, AaniOikealle, null, new Vector());
            Keyboard.Listen(Key.A, ButtonState.Released, LopetaAaniVasemmalle, null, new Vector());
            Keyboard.Listen(Key.D, ButtonState.Released, LopetaAaniOikealle, null, new Vector());
            
            Keyboard.Listen(Key.A, ButtonState.Down, LiikuVasemmalle, null, new Vector());
            Keyboard.Listen(Key.D, ButtonState.Down, LiikuOikealle, null, new Vector());
            Keyboard.Listen(Key.W, ButtonState.Pressed, Hyppaa, null, new Vector());
            Keyboard.Listen(Key.Escape, ButtonState.Pressed, ConfirmExit, "Lopeta peli");
            
            Keyboard.Listen(Key.Space, ButtonState.Pressed, LuoPesismaila, "", new Vector(90, 10), _pelaaja);
        }


        /// <summary>
        /// aliohjelma luo tiili-palikoita, joista kenttä rakentuu
        /// </summary>
        /// <param name="paikka">palikan paikka</param>
        /// <param name="leveys">palikan korkeus</param>
        /// <param name="korkeus">palikan leveys</param>
        private void LuoTaso(Vector paikka, double leveys, double korkeus)
        {
            PhysicsObject taso = PhysicsObject.CreateStaticObject(leveys, korkeus);
            taso.Position = paikka;
            taso.CollisionIgnoreGroup = 2;
            taso.Color = Color.Gray;
            taso.Image = _tiiliseinakuva;
            taso.Tag = "taso";
            Add(taso);
        }

        
        /// <summary>
        /// Aliohjelma, jossa luodaan seuraavaan kenttään vievä ovi
        /// </summary>
        /// <param name="paikka">oven paikka</param>
        /// <param name="x">oven leveys</param>
        /// <param name="y">oven korkeus</param>
        private void LuoExit(Vector paikka, double x, double y)
        {
            _exit = PhysicsObject.CreateStaticObject(100, 150);
            _exit.Position = paikka;
            _exit.CollisionIgnoreGroup = 2;
            _exit.Color = Color.HotPink;
            _exit.Tag = "exit";
            _exit.Image = _uloskaynti;
            Add(_exit);
        }
        
        
        /// <summary>
        /// pelaajaa vahingoittavan ansan luova aliohjelma
        /// </summary>
        /// <param name="paikka">ansan paikka</param>
        /// <param name="x">ansan leveys</param>
        /// <param name="y">ansan korkeus</param>
        private void LuoAnsa(Vector paikka, double x, double y)
        {
            _ansa = PhysicsObject.CreateStaticObject(100, 150);
            _ansa.CollisionIgnoreGroup = 2;
            _ansa.Position = paikka;
            _ansa.Image = _ansakuva;
            _ansa.Tag = "ansa";
            Add(_ansa);
        }

        
        /// <summary>
        /// Tekee kentälle koristeita
        /// </summary>
        /// <param name="kuuskulmio">mille alueelle koriste tehdään</param>
        /// <returns>koriste</returns>
        public static GameObject TeeKoriste(BoundingRectangle kuuskulmio)
        {
            GameObject koriste = new GameObject(400, 400, Shape.Hexagon);
            koriste.Position = RandomGen.NextVector(kuuskulmio);
            koriste.Color = Color.Rose;
            return koriste;
        }
        

        /// <summary>
        /// Aliohjelma luo pelaajaa parantavan viinapllon
        /// </summary>
        /// <param name="paikka">pullon paikka</param>
        /// <param name="x">pullon leveys</param>
        /// <param name="y">pullon korkeus</param>
        private void LuoViinapullo(Vector paikka, double x, double y)
        {
            _viinapullo = PhysicsObject.CreateStaticObject(50, 50);
            _viinapullo.Position = paikka;
            _viinapullo.Color = Color.White;
            _viinapullo.Tag = "Viinapullo";
            _viinapullo.Image = _viinapullokuva;
            Add(_viinapullo);
        }

        
        /// <summary>
        /// Aliohjelma luo "haamupalikan" jonka sijaintiin kelabotti myöhemmin luodaan
        /// </summary>
        /// <param name="paikka">palikan paikka</param>
        /// <param name="leveys">palikan leveys</param>
        /// <param name="korkeus">palikan korkeus</param>
        private void LuoKelabottiSpawni(Vector paikka, double leveys, double korkeus)
        {
            PhysicsObject bottispawni = PhysicsObject.CreateStaticObject(leveys, korkeus);
            bottispawni.Position = paikka;
            bottispawni.IgnoresCollisionResponse = true;
            //BottiSpawni.CollisionIgnoreGroup = 3;
            bottispawni.IsVisible = false;
            bottispawni.IgnoresGravity = true;
            Add(bottispawni, -1);
            _spawnipaikat.Add(bottispawni);
        }
        
      
        /// <summary>
        /// Aliohjelma, jossa luodaan pelaaja
        /// </summary>
        /// <param name="paikka">pelaajan paikka</param>
        /// <param name="x">pelaajan x-koordinaatti</param>
        /// <param name="y">pelaajan y-koordinaatti</param>
        /// <returns>pelaaja</returns>
        private void LuoPelaaja(Vector paikka, double x, double y)
        {
            _pelaaja = new PlatformCharacter(50.0, 100.0);
            _pelaaja.Mass = 1.0;
            _pelaaja.Shape = Shape.Rectangle;
            _pelaaja.Color = Color.Black;
            _pelaaja.Position = paikka;
            _pelaaja.CollisionIgnoreGroup = 1;
            _pelaaja.AnimWalk = new Animation(_henkiloSaapastelu);
            _pelaaja.AnimIdle = new Animation(_paikallaanAnimaatio);
            _pelaaja.AnimWalk.FPS = 3;
            _pelaaja.AnimFall = new Animation(_putoamisAnimaatio);
            _pelaaja.AnimFall.FPS = 12;
            _pelaaja.LoopFallAnim = true;
          
            // Törmäyksen käsittelijä, mitä tapahtuu, kun pelaaja osuu kelabotiin 
            //Siis pelaajan elämien väheneminen VahnigoitaPelaajaa-aliohjelman mukaisesti 
            AddCollisionHandler(_pelaaja, "Kelabotti", VahingoitaPelaajaa);
            AddCollisionHandler(_pelaaja, "Viinapullo", ParannaPelaajaa);
            AddCollisionHandler(_pelaaja, "kappale", VahingoitaPelaajaa);
            AddCollisionHandler(_pelaaja, "exit", KentanVaihto);
            AddCollisionHandler(_pelaaja, "ansa", VahingoitaPelaajaa);
            
            Add(_pelaaja);
        }
        
        
        /// <summary>
        /// Aliohjelma, joka luo pelaajalle elämälaskurin ja sen nimen: "Mielenterveys"
        /// </summary>
        private void LuoElamalaskuri()
        {
            _pelaajanElamaaskuri = new DoubleMeter(100.0);
            _pelaajanElamaaskuri.MaxValue = 100;
            _pelaajanElamaaskuri.LowerLimit += ElamaLoppui;

            ProgressBar elamapalkki = new ProgressBar(150, 18);
            elamapalkki.X = Screen.Left + 110;
            elamapalkki.Y = Screen.Bottom + 50;
            elamapalkki.BindTo(_pelaajanElamaaskuri);
            elamapalkki.Color = Color.Red;
            elamapalkki.BarColor = Color.Green;
            elamapalkki.BorderColor = Color.Black;
            Label tekstikentta = new Label(200, 10, "Mielenterveys");
            tekstikentta.X = Screen.Left + 100;
            tekstikentta.Y = Screen.Bottom + 70;
            tekstikentta.Font = new Font(20);
            Add(tekstikentta);
            Add(elamapalkki);
        }
        
        
        /// <summary>
        /// Aliohjelma, joka käsittelee pelaajan kuoleman ja ilmoittaa pelin loppumisen
        /// </summary>
        private void ElamaLoppui()
        {
            Label kuolema = new Label(800, 60, "Toimeentulohakemus hylätty.");
            kuolema.Y = 140;
            kuolema.Font = new Font(60);
            kuolema.TextColor = Color.Red;
            //Kuolema.Color = Color.Black;
            Add(kuolema);
        }
        

        /// <summary>
        /// Pesismailan luominen
        /// </summary>
        /// <param name="koko">Pesismailan koko</param>
        /// <param name="pelaaja">kohde, johon Pesismaila liitetään</param>
        private void LuoPesismaila(Vector koko, PlatformCharacter pelaaja)
        {
            _pesismaila = new PhysicsObject(koko.X, koko.Y);
            _pesismaila.Position = pelaaja.Position + new Vector(80*pelaaja.FacingDirection.GetVector().X, 10);
            _pesismaila.CollisionIgnoreGroup = 1;
            _pesismaila.Mass = 1;
            _pesismaila.Tag = "Pesismaila";
            Add(_pesismaila);
            _pesismaila.LifetimeLeft = TimeSpan.FromSeconds(0.075);
            Sound lyontiaani2 = _lyontiaani.CreateSound();
            lyontiaani2.Volume = 1;
            lyontiaani2.Play();
            _pesismaila.IgnoresGravity = true;
            
            //PISTEET ei elämät
            AddCollisionHandler(_pesismaila, "Kelabotti", KunVihollinenTuhoutuu);
        }

        
        /// <summary>
        /// Tämä funktio luo Kelabotti-vihun ja sille annetaan pelaajan seuraamisaivot
        /// </summary>
        private void LuoKelabotti()
        {
            PhysicsObject spawni = _spawnipaikat[RandomGen.NextInt(_spawnipaikat.Count)];
            _kelabotti = new PlatformCharacter(50.0, 100.0);
            _kelabotti.Color = Color.Orange;
            _kelabotti.Image = _kelabottikuva;
            _kelabotti.CollisionIgnoreGroup = 3;
            _kelabotti.Tag = "Kelabotti";
            _kelabotti.Position = spawni.Position;
            _kelabotti.AnimWalk = new Animation(_kelabottiKavely);
            _kelabotti.AnimWalk.FPS = 3;
            Add(_kelabotti);
            
            FollowerBrain seuraajanAivot = new FollowerBrain(_pelaaja);
            seuraajanAivot.Speed = 100;

            _kelabotti.Brain = seuraajanAivot;
            
            Timer heittoajastin = new Timer();
            heittoajastin.Interval = 2;
            heittoajastin.Timeout += delegate() { KelabotinAmmus(_kelabotti, "pelaaja"); };
            heittoajastin.Start();
            
            _kelabotti.Destroyed += heittoajastin.Stop;
        }
        
        
       /// <summary>
       /// Aliohjelma, jossa käsitellään Kelabotin heittämä ammus
       /// </summary>
       /// <param name="heittavaOlio">Kelabotti heittää ammuksen</param>
       /// <param name="kohdeolionTunniste">pelaajan tunniste</param>
        private void KelabotinAmmus(PhysicsObject heittavaOlio, string kohdeolionTunniste)
        {
            _kappale = new PhysicsObject(15, 15, Shape.Triangle);
            _kappale.Hit(new Vector(180*_pelaaja.FacingDirection.GetVector().X, 10));
            _kappale.Position = heittavaOlio.Position;
            _kappale.CollisionIgnoreGroup = 3;
            _kappale.Color = Color.Silver;
            _kappale.Tag = "kappale";
            _kappale.MaximumLifetime = TimeSpan.FromSeconds(1.5);
            Add(_kappale);
        }

        
        /// <summary>
        /// Tämä aliohjelma käsittlee sen, kun pelaaja osuu Kelabottiin
        /// </summary>
        /// <param name="pelaaja">pelaajahahmo</param>
        /// <param name="Kelabotti">pelin vihu; Kelabotti</param>
        private void VahingoitaPelaajaa(PhysicsObject pelaaja, PhysicsObject kappale)
        {
            int luku = RandomGen.NextInt(19, 34);
            _pelaajanElamaaskuri.Value = _pelaajanElamaaskuri - luku; // Vähentää pelaajan elämää satunnaisen määrän
            
            if (_pelaajanElamaaskuri.Value <= 0) //jos laskuri menee nollaan... 
            { 
                pelaaja.Destroy(); //...ja pelaaja tuhotaan
                //Pesismaila.Destroy();//...myös pesismaila
            } 
        }
        
        
        /// <summary>
        /// Aliohjelma, joka parantaa pelaajan, kun tämä koskee viinapulloa
        /// </summary>
        /// <param name="pelaaja">kohde, joka parannetaan</param>
        /// <param name="Viinapullo">parantava esine</param>
        private void ParannaPelaajaa(PhysicsObject pelaaja, PhysicsObject viinapullo)
        {
            //Viinapullo.CollisionIgnoreGroup = 1;
            
            if (_pelaajanElamaaskuri.Value < 99)
            {
                //Viinapullo.CollisionIgnoreGroup = 0;
                _viinapulloaani.Play();
                _pelaajanElamaaskuri.Value = _pelaajanElamaaskuri.Value + 20;
                _pisteet.Value += 20;
                viinapullo.Destroy();
            }
        }
        
        
        /// <summary>
        /// Luo pistelaskurin pisteille, joita saa kun hakkaa kelabotteja
        /// </summary>
        private void LuoPistelaskuri() 
        { 
            Label opintoNopat = new Label(150, 50, "Opintonopat:");
            opintoNopat.X = Screen.Left + 100;
            opintoNopat.Y = Screen.Bottom + 93;
            opintoNopat.Font = new Font(20);
            opintoNopat.TextColor = Color.Black;
            Add(opintoNopat);
            
            _pisteet = new IntMeter(0); // Aloitetaan nollasta
            _pisteNaytto = new Label(); 
            _pisteNaytto.X = Screen.Left + 170;  
            _pisteNaytto.Y = Screen.Bottom + 95;  
            _pisteNaytto.TextColor = Color.OrangeRed; 
            _pisteNaytto.Font = new Font(20); 
            _pisteNaytto.BindTo(_pisteet); // Päivitetään teksti automaattisesti 
            Add(_pisteNaytto);
        } 
        
        
        /// <summary>
        /// Käsittelee kelabotin tuhoamisen ja antaa siitö pisteitä
        /// </summary>
        /// <param name="pelaaja">pelaajahahmo</param>
        /// <param name="kelabotti">pelin vihu; Kelabotti</param>
        private void KunVihollinenTuhoutuu(PhysicsObject pelaaja, PhysicsObject kelabotti)
        {
            _keladamageaani.Play();
            _pisteet.Value += 100; // Lisää esim. 100 pistettä, kun botti tuhotaan
            
            kelabotti.Destroy(); // Poistaa botin näytöltä
        }

        
        /// <summary>
        /// Aliohjelma, jossa käsitellään kentän vaihto
        /// </summary>
        /// <param name="pelaaja">pelaaja</param>
        /// <param name="exit">esine, josta kenttä vaihtuu</param>
        private void KentanVaihto(PhysicsObject pelaaja, PhysicsObject exit)
        {
            if (_pisteet.Value >= 300)
            
            {
                _kenttanumero++;
                LuoKentta(_kenttanumero);
            }
        }
    }