using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using MySql.Data.MySqlClient;
using Org.BouncyCastle.Asn1.X500;

namespace SpaceInvaders
{
    
    public class Game
    {
        ///////////////////////////////////////////////////////////Déclaration des variabes////////////////////////////////////////
        Random random = new Random();
        DropMisil? drop;
        const int maxScore = 1000;                        //Limite des points
        public int intHPlayerPosition = Console.WindowWidth / 2; //Position horizontal du joueur
        int intVPlayerPosition = Console.WindowHeight - 2;//Position vertical du joueur
        int intVPlayerMisil = Console.WindowHeight - 4;   //Position vertical du missile
        int intHPlayerMisil;                              //Position horizontal du missile
        int intVMonsterPosition = 10;                      //Position vertical du monstre
        int intScoreJoueur = 0;                           //Points du joueur
        int intidJoueur = 0;                              //Id du joueur
        int intHPositionEnnemi;                           //Position horizontal de l'ennemi
        int intPointsParEnnemi = 100;                     //
        byte bytEspacement = 1;                           //Espacement entre les ennemis
        byte bytDirectionEnnemi = 0;                      //Dirige la direction des ennmis
        int bytNbVies = 5;                               //Vies du joeurs
        byte bytPosMaxScore = 0;                          //Position du score maximal
        byte bytPosScore = 20;                            //Position du score
        byte bytPosVie = 40;                              //Position des vies
        string strSkinJoueur = "__/";                     //Joueur
        string strNomJoueur = "";                         //Nom du joueur
        string strEnnemi = "X";                           //Ennemi
        string strPlayerMisil = "*";                      //Attaque ennemi
        bool booAtaqueActif = false;                      //Ataque actif
        bool booJeuActif = true;                          //Jeu actif
        bool booMonstreActif = true;                      //Mouvement du monstre
        object missileLock = new object();                //Traffic
        List<(int x, int y)> activeMissilesJoueur = new List<(int x, int y)>();             //Liste des missiles du joueur
        List<(int x, int y)> activeEnemies = new List<(int x, int y)>();                    //Liste des monstres
        public List<(string Name, int Score)> playerScores = new List<(string Name, int Score)>(); //liste contenant le nom et le score
        List<DropMisil> missilesEnnemis = new List<DropMisil>();                            //List des misiles de l'ennemi
        System.Timers.Timer attackTimer;                                                    //Vitesse
        
        /////////////////////////////////////////////////Code principale///////////////////////////////////////////////////////////
        ///
        /// <summary>
        /// Déroulement du jeu
        /// </summary>
        public void StartGame()
        {
             random = new Random();
             intHPlayerPosition = Console.WindowWidth / 2; //Position horizontal du joueur
             intVPlayerPosition = Console.WindowHeight - 2;//Position vertical du joueur
             intVPlayerMisil = Console.WindowHeight - 4;   //Position vertical du missile
             intVMonsterPosition = 1;                      //Position vertical du missile du monstre
             intScoreJoueur = 0;                           //Points du joueur
             intidJoueur = 0;                              //Id du joueur
             intPointsParEnnemi = 100;                     //Points reçus par impact
             bytEspacement = 1;                            //Espacement entre les ennemis
             bytDirectionEnnemi = 0;                       //Dirige la direction des ennmis
             bytNbVies = 5;                                //Vies du joeurs
             bytPosMaxScore = 0;                           //Position du score maximal
             bytPosScore = 20;                             //Position du score
             bytPosVie = 40;                               //Position des vies
             strSkinJoueur = "__/";                        //Joueur
             strNomJoueur = "";                            //Nom du joueur
             strEnnemi = "X";                              //Ennemi
             strPlayerMisil = "*";                         //Attaque ennemi
             booAtaqueActif = false;                       //Ataque actif
             booJeuActif = true;                           //Jeu actif
             booMonstreActif = true;                       //Mouvement du monstre
             missileLock = new object();                   //Traffic
            activeMissilesJoueur = new List<(int x, int y)>();             //Liste des missiles du joueur
            activeEnemies = new List<(int x, int y)>();                    //Liste des monstres
            missilesEnnemis = new List<DropMisil>();                       //List des misiles de l'ennemi

            GetPlayerName();
            Console.CursorVisible = false;
            Thread playerThread = new Thread(Player);
            Thread monsterThread = new Thread(Monster);

            playerThread.Start();
            monsterThread.Start();

            while (booJeuActif)
            {
                Thread.Sleep(100); // Permet de ralentir la vitesse du procès
            }
            
            Console.CursorVisible = true;
            AddPlayerScore();
            Thread.Sleep(5000);
        }
        /// <summary>
        /// Obtention du nom du joueur
        /// </summary>
        public void GetPlayerName()
        {
            Console.WriteLine("Pseudo:");
            strNomJoueur = Console.ReadLine();
            intidJoueur += 1;
            Console.Clear();
        }
        /// <summary>
        /// Vitesse de l'attaque
        /// </summary>
        public void Timer()
        {
            attackTimer = new System.Timers.Timer();
            attackTimer.Elapsed += (sender, e) => PlayerAttack(sender, e);
            attackTimer.Interval = 100;
            attackTimer.AutoReset = true;
            attackTimer.Enabled = true;
        }
    
        /// <summary>
        /// Attaque du joueur
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void PlayerAttack(object sender, ElapsedEventArgs e)
        {
            if (HasReachedMaxScore()&& PlayerDie())
            {
                attackTimer.Stop();
                attackTimer.Dispose();
                attackTimer = null;
                return;
            }
            

            for (int i = activeMissilesJoueur.Count - 1; i >= 0; i--)
            {
                int x, y; 

                lock (missileLock)
                {
                    x = activeMissilesJoueur[i].x;
                    y = activeMissilesJoueur[i].y;
                }

                SuperConsole.WriteAtPosition(x, y, " ");

                if (HasReachedMaxScore()&& PlayerDie())
                {
                    attackTimer.Stop();
                    attackTimer.Dispose();
                    attackTimer = null;
                    return;
                }

                if (y > 1)
                {
                    y--;

                    // Colision de l'ennemi

                    var impactedEnemy = CheckCollision(x, y);

                    if (impactedEnemy != (-1, -1))
                    {
                        lock (missileLock)
                        {
                            activeMissilesJoueur.RemoveAt(i);
                            activeEnemies.Remove(impactedEnemy);
                        }
                        AddPoints(intPointsParEnnemi);
                        
                        if (HasReachedMaxScore() && PlayerDie())
                        {
                            Console.Clear();
                            ReturnToMainMenu();
                            break;
                        }
                    }
                    else
                    {
                        SuperConsole.WriteAtPosition(x, y, strPlayerMisil);
                        lock (missileLock)
                        {
                            activeMissilesJoueur[i] = (x, y);
                        }
                    }
                }
                else
                {
                    lock (missileLock)
                    {
                        activeMissilesJoueur.RemoveAt(i);
                    }
                }
            }

        }
        /// <summary>
        /// Joueur
        /// </summary>
        public void Player()
        {
            
            SuperConsole.WriteAtPosition(intHPlayerPosition, intVPlayerPosition, strSkinJoueur);
            while (!HasReachedMaxScore()&&!PlayerDie())
            {
                if (Console.KeyAvailable)
                {
                    var key = Console.ReadKey(true);
                    if (key.Key == ConsoleKey.RightArrow)
                    {
                        int intPlayerPosition = 0;
                        if (intHPlayerPosition < Console.WindowWidth- strSkinJoueur.Length)
                        {
                            foreach (char chrPSkinCaracteres in strSkinJoueur)
                            {
                                intPlayerPosition++;
                                SuperConsole.WriteAtPosition(intHPlayerPosition - intPlayerPosition, intVPlayerPosition, " ");
                            }
                            intHPlayerPosition++;
                            SuperConsole.WriteAtPosition(intHPlayerPosition - strSkinJoueur.Length+2, intVPlayerPosition, strSkinJoueur);
                            Thread.Sleep(20);
                        }
                        else
                        {
                            intHPlayerPosition--;
                            Console.SetCursorPosition(intPlayerPosition, intVPlayerPosition);
                        }
                    }

                    if (key.Key == ConsoleKey.LeftArrow)
                    {
                        int intPlayerPosition = 0;
                        if (intHPlayerPosition > strSkinJoueur.Length)
                        {
                            foreach (char chrSkinCaracteres in strSkinJoueur)
                            {
                                intPlayerPosition--;
                                SuperConsole.WriteAtPosition(intHPlayerPosition + intPlayerPosition + strSkinJoueur.Length, intVPlayerPosition, " ");
                            }
                            intHPlayerPosition--;
                            SuperConsole.WriteAtPosition(intHPlayerPosition - strSkinJoueur.Length+2, intVPlayerPosition, strSkinJoueur);
                            Thread.Sleep(20);
                        }
                        else
                        {
                            intHPlayerPosition++;
                            Console.SetCursorPosition(intPlayerPosition, intVPlayerPosition);
                        }
                    }
                    if (key.Key == ConsoleKey.Spacebar)
                    {
                        intHPlayerMisil = intHPlayerPosition;
                        int x = intHPlayerMisil;
                        int y = intVPlayerMisil;

                        activeMissilesJoueur.Add((x, y));

                        if (attackTimer == null)
                        {
                            Timer();
                        }
                        Thread.Sleep(100);
                    }
                }
            }
            while (HasReachedMaxScore()&& PlayerDie())
            {
                if (Console.KeyAvailable)
                {
                    var key = Console.ReadKey(true);
                    if (key.Key == ConsoleKey.RightArrow || key.Key == ConsoleKey.LeftArrow || key.Key == ConsoleKey.Spacebar)
                    {
                        // Empêche au jouer de se déplacer
                    }
                }
            }
        }

        /// <summary>
        /// Ennemi
        /// </summary>
        public void Monster()
        {
            byte bytNombreEnnemi = (byte)random.Next(1, 14);
            int[] PatatePosition = new int[bytNombreEnnemi];

            SuperConsole.WriteAtPosition(bytPosMaxScore, 0, $"P:Win {maxScore}");
            SuperConsole.WriteAtPosition(bytPosScore, 0, "P: 0");
            SuperConsole.WriteAtPosition(bytPosVie, 0, "<3: 5");
            for (int i = 0; i < bytNombreEnnemi; i++)
            {
                PatatePosition[i] = i * (strEnnemi.Length + bytEspacement);
            }

            while (booMonstreActif)
            {
                if (bytDirectionEnnemi == 0)
                {
                    for (int i = 0; i < bytNombreEnnemi; i++)
                    {
                        intHPositionEnnemi = PatatePosition[i];

                        if (intHPositionEnnemi >= 0 && intHPositionEnnemi + strEnnemi.Length < Console.WindowWidth)
                        {  
                            SuperConsole.WriteAtPosition(intHPositionEnnemi, intVMonsterPosition, " ");
                            Console.Write(strEnnemi);
                            activeEnemies.Add((intHPositionEnnemi, intVMonsterPosition));

                        }
                    }

                    for (int i = 0; i < bytNombreEnnemi; i++)
                    {
                        PatatePosition[i]++;
                    }

                    intHPositionEnnemi = PatatePosition[bytNombreEnnemi - 1];

                    if (intHPositionEnnemi + strEnnemi.Length >= Console.WindowWidth)
                    {
                        intVMonsterPosition++;
                        if (intVMonsterPosition < Console.WindowHeight)
                        {
                            Console.SetCursorPosition(0, intVMonsterPosition - 1);
                            Console.Write(new string(' ', Console.WindowWidth));
                        }
                        bytDirectionEnnemi += 1;
                    }
                }
                else if (bytDirectionEnnemi == 1)
                {
                    for (int i = 0; i < bytNombreEnnemi; i++)
                    {
                        intHPositionEnnemi = PatatePosition[i];

                        if (intHPositionEnnemi >= 0 && intHPositionEnnemi + strEnnemi.Length < Console.WindowWidth )
                        {
                            SuperConsole.WriteAtPosition(intHPositionEnnemi, intVMonsterPosition, strEnnemi);
                            intHPositionEnnemi += strEnnemi.Length;

                            for (int j = 0; j < bytEspacement; j++)
                            {
                                SuperConsole.WriteAtPosition(intHPositionEnnemi, intVMonsterPosition, " ");
                                intHPositionEnnemi++;
                            }
                        }
                    }

                    for (int i = 0; i < bytNombreEnnemi; i++)
                    {
                        PatatePosition[i]--;
                    }

                    if (PatatePosition[0] < 10)
                    {
                        intVMonsterPosition++;

                        if (intVMonsterPosition < Console.WindowHeight)
                        {
                            Console.SetCursorPosition(0, intVMonsterPosition - 1);
                            Console.Write(new string(' ', Console.WindowWidth));
                        }
                        bytDirectionEnnemi -= 1;
                    }
                }
                if (ShouldMonsterAttack() && activeEnemies.Count > 0)
                {
                    
                    var attackingMonsterIndex = random.Next(activeEnemies.Count);
                    var attackingMonster = activeEnemies[attackingMonsterIndex];
                    int missileStartX = attackingMonster.x;
                    int missileStartY = attackingMonster.y + 1; 

                   
                    missilesEnnemis.Add(new DropMisil(missileStartX, missileStartY));
                }

                
                for (int i = missilesEnnemis.Count - 1; i >= 0; i--)
                {
                    bool missileHasDisappeared = missilesEnnemis[i].MonsterAttack();
                    if (missileHasDisappeared)
                    {
                        
                        missilesEnnemis.RemoveAt(i);
                    }
                }
                HandleEnemyMissileCollisions();
                if (PlayerDie())
                {
                    Console.Clear();
                    ReturnToMainMenu();
                    break;
                }

                Thread.Sleep(200);
            }
        }
        /// <summary>
        /// Verifie s'il y a eu une colision
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public (int x, int y) CheckCollision(int x, int y)
        {
            // 
            foreach (var enemyPosition in activeEnemies)
            {
                if (x >= enemyPosition.x && x < enemyPosition.x + strEnnemi.Length && y == enemyPosition.y)
                {
                    return enemyPosition; // Colision avec l'ennemi
                }
            }
            return (-1, -1); // Pas colision
        }
        public bool CheckEnemyMissileCollision(DropMisil enemyMissile)
        {
            int playerLeftEdge = intHPlayerPosition - (strSkinJoueur.Length / 2);
            int playerRightEdge = intHPlayerPosition + (strSkinJoueur.Length / 2) - 1; 

            if (enemyMissile.PblintVMonsterMisil == intVPlayerPosition &&
                enemyMissile.PblintHMonsterMisil >= playerLeftEdge &&
                enemyMissile.PblintHMonsterMisil <= playerRightEdge)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// Dirige les colisions
        /// </summary>
        public void HandleEnemyMissileCollisions()
        {
            for (int i = missilesEnnemis.Count - 1; i >= 0; i--)
            {
                DropMisil enemyMissile = missilesEnnemis[i];
                if (CheckEnemyMissileCollision(enemyMissile))
                {
                    RestLive(-1); 
                    missilesEnnemis.RemoveAt(i); 
                }
            }
        }
        /// <summary>
        /// Ponctuation maximale
        /// </summary>
        /// <returns></returns>
        public bool HasReachedMaxScore()
        {
            if (intScoreJoueur >= maxScore)
            {
                booMonstreActif = false; // Arrête l'ennemi
                booJeuActif = false; // Arrête le jeu
                return true;
            }
            return false;

        }
        /// <summary>
        /// Le joueur meurt
        /// </summary>
        /// <returns></returns>
        public bool PlayerDie()
        {
            if (bytNbVies <= 0)
            {
                booMonstreActif = false; // Arrête l'ennemi
                booJeuActif = false; // Arrête le jeu
                return true;
            }
            return false;

        }

        /// <summary>
        /// sommes des points
        /// </summary>
        /// <param name="pointsToAdd"></param>
        public void AddPoints(int pointsToAdd)
        {
            intScoreJoueur += pointsToAdd;
            UpdateScoreDisplay();
        }

        /// <summary>
        /// enlève des vies
        /// </summary>
        /// <param name="RestLive"></param>
        public void RestLive(int RestLive)
        {
            bytNbVies += RestLive;
            UpdateLiveDisplay();
        }

        /// <summary>
        /// Probabilité de lancer des attaques
        /// </summary>
        private bool ShouldMonsterAttack()
        {           
            return new Random().Next(100) < 10; 
        }

        /// <summary>
        /// Mise à jour du score
        /// </summary>
        public void UpdateScoreDisplay()
        {
            SuperConsole.WriteAtPosition(bytPosScore, 0, $"P: {intScoreJoueur}    "); 
        }
        /// <summary>
        /// Mise à jour des vies
        /// </summary>
        public void UpdateLiveDisplay()
        {
            SuperConsole.WriteAtPosition(bytPosVie, 0, $"<3: {bytNbVies}    ");
        }

        /// <summary>
        /// Mise à jour du score
        /// </summary>
        public void AddPlayerScore()
        {
            playerScores.Add((strNomJoueur, intScoreJoueur));
        }
        /// <summary>
        /// Fin du jeu
        /// </summary>
        public void ReturnToMainMenu()
        {
            Console.Clear();
            if(intScoreJoueur >= maxScore)
            {
                SuperConsole.WriteAtPosition(bytPosMaxScore, 0, $"P:Win {maxScore}");
                SuperConsole.WriteAtPosition(bytPosScore, 0, $"P: {intScoreJoueur}    ");
                SuperConsole.WriteAtPosition(bytPosVie, 0, $"<3: {bytNbVies}    ");
                SuperConsole.WriteAtPosition(Console.WindowWidth / 2, Console.WindowHeight / 2, $"Félicitations");
            }
            else
            {
                SuperConsole.WriteAtPosition(bytPosMaxScore, 0, $"P:Win {maxScore}");
                SuperConsole.WriteAtPosition(bytPosScore, 0, $"P: {intScoreJoueur}    ");
                SuperConsole.WriteAtPosition(bytPosVie, 0, $"<3: {bytNbVies}    ");
                SuperConsole.WriteAtPosition(Console.WindowWidth / 2, Console.WindowHeight / 2, $"GAME OVER");
            }
            Thread.Sleep(5000);
            Console.Clear();
            booJeuActif = false;
        }

        /// <summary>
        /// Liste des points
        /// </summary>
        /// <returns></returns>
        public string Highscore()
        {
            //Obtien les valeurs du joueur
            if(playerScores.Count!= 0)
            {
                string sql = "INSERT INTO t_joueur (idJoueur, jouPseudo, jouNombrePoints)" +
                    "VALUES(" + new Random().Next(100,10000) + ", '" + playerScores[intidJoueur - 1].Name + 
                    "', " + playerScores[intidJoueur - 1].Score + ");";
                return sql;
            }
            return null;
            
        }
    }
}
