using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System.Runtime.CompilerServices;
using System.Threading;
using UnityEngine.EventSystems;
using System.Linq;
using System.Runtime.ConstrainedExecution;

public class Game : MonoBehaviour
{
    private GameObject _initobject;
    private PreGame _initobjectsqrt;
    private GameObject _pawnscore;
    private GameObject _pawn;
    private GameObject _currentpawn;
    private Vector2 _directionp;
    private Vector2 _rootbuttonp;
    private Vector2 _numberrevealedp;
    private Vector2 _sumrevealedp;
    private Vector2 _rootrevealedp;
    private Vector2 _winnerrevealedp;
    private Vector2 _nextroundbuttonp;
    private Vector2 _ultimatewinnerp;
    private Vector2 _nextgamep;

    List<numberedbox> ppnum;
    pawnbox ppg;
    public float timer;
    public bool istimerrunning = false;
    public bool haspawnpick = false;
    public bool reveal = false;
    public uint pawnroundset = 0;

    List<float> comparer;
    float rootresult;
    float sumresult;
    float winner;
    List<pawn> winners;
    uint roundcounter = 1;

    void Start()
    {
        _initobject = GameObject.Find("init"); //settings object onhold from 
        _initobjectsqrt = _initobject.transform.GetComponent<PreGame>();

        _initround(); //capture initial object
        _resetround(); //throw all object away
        _generatepawn(); //generate the pawns
        _generatenumberbutton(); //number selection UI. yes it generated
        _hidenumberboard(); //hide the number selection UI until it called
    }

    void Update()
    {

    }

    void FixedUpdate()
    {
        //timer monitoring for numberselection
        if (istimerrunning)
        {
            if (timer > 0)
            {
                timer -= Time.deltaTime;
                float minutes = Mathf.FloorToInt((timer + 1) / 60);
                float seconds = Mathf.FloorToInt((timer % 60));
                GameObject.Find("timer").GetComponent<Text>().text = string.Format("{00:00}:{01:00}", minutes, seconds);
            }
            else
            {
                timer = 0;
                istimerrunning = false;
                _locknumber();
            }
        }

        //checking if all pawn already choose a number
        //instantly show the ROOT IT!
        if (pawnroundset >= (ppg.pawns - ppg.eliminiateds) && !reveal)
        {
            GameObject.Find("direction").GetComponent<RectTransform>().localPosition = new Vector2
            {
                x = 5000,
                y = 5000
            };
            GameObject.Find("rootbutton").GetComponent<RectTransform>().localPosition = _rootbuttonp;
        }
        else if (pawnroundset < (ppg.pawns - ppg.eliminiateds) && !reveal)
        {
            GameObject.Find("direction").GetComponent<RectTransform>().localPosition = _directionp;
            GameObject.Find("rootbutton").GetComponent<RectTransform>().localPosition = new Vector2
            {
                x = 5000,
                y = 5000
            };
        }
    }

    /* initial capture of position to mess with */
    public void _initround()
    {
        GameObject.Find("roundtext").GetComponent<Text>().text = "Round 1"; //set default first round indicator

        //a bunch of object location
        _directionp = GameObject.Find("direction").GetComponent<RectTransform>().localPosition; 
        _rootbuttonp = GameObject.Find("rootbutton").GetComponent<RectTransform>().localPosition;
        _numberrevealedp = GameObject.Find("numberrevealed").GetComponent<RectTransform>().localPosition;
        _sumrevealedp = GameObject.Find("sumrevealed").GetComponent<RectTransform>().localPosition;
        _rootrevealedp = GameObject.Find("rootrevealed").GetComponent<RectTransform>().localPosition;
        _winnerrevealedp = GameObject.Find("winnerrevealed").GetComponent<RectTransform>().localPosition;
        _nextroundbuttonp = GameObject.Find("nextroundbutton").GetComponent<RectTransform>().localPosition;
        _ultimatewinnerp = GameObject.Find("ultimatewinner").GetComponent<RectTransform>().localPosition;
        _nextgamep = GameObject.Find("nextgame").GetComponent<RectTransform>().localPosition;
    }

    /* reset round state. should be able to simplify this */
    public void _resetround()
    {
        timer = 0; //reset timer
        istimerrunning = false; //disable timer
        pawnroundset = 0; //disable round lock
        //haspawnpick = false; 
        reveal = false; //hide the thruth

        //reset pawn state
        if (ppg != null)
        {
            foreach (pawn ppm in ppg.p)
            {
                ppm._haspicked = false;
                ppm._number = 0;
                ppm._pawnobject.transform.Find("icon").transform.Find("pawnnumber").GetComponent<Text>().text = "";
                if (!ppm._eliminated) { ppm._pawnobject.transform.Find("icon").GetComponent<Button>().interactable = true; }
                ppm._pawnobject.transform.Find("winner").position = new Vector2
                {
                    x = 5000,
                    y = 5000
                };
            }
        }

        //throw everything i don't want to see far far far away
        GameObject.Find("rootbutton").GetComponent<RectTransform>().localPosition = new Vector2
        {
            x = 5000,
            y = 5000
        };
        GameObject.Find("numberrevealed").GetComponent<RectTransform>().localPosition = new Vector2
        {
            x = 5000,
            y = 5000
        };
        GameObject.Find("sumrevealed").GetComponent<RectTransform>().localPosition = new Vector2
        {
            x = 5000,
            y = 5000
        };
        GameObject.Find("rootrevealed").GetComponent<RectTransform>().localPosition = new Vector2
        {
            x = 5000,
            y = 5000
        };
        GameObject.Find("winnerrevealed").GetComponent<RectTransform>().localPosition = new Vector2
        {
            x = 5000,
            y = 5000
        };
        GameObject.Find("nextroundbutton").GetComponent<RectTransform>().localPosition = new Vector2
        {
            x = 5000,
            y = 5000
        };
        GameObject.Find("ultimatewinner").GetComponent<RectTransform>().localPosition = new Vector2
        {
            x = 5000,
            y = 5000
        };
        GameObject.Find("nextgame").GetComponent<RectTransform>().localPosition = new Vector2
        {
            x = 5000,
            y = 5000
        };

        //reset a bunch of UI component state
        GameObject.Find("boardbase").GetComponent<Image>().color = ColorSpace.ppwhiteblock;
        GameObject.Find("result").GetComponent<Image>().sprite = Resources.Load<Sprite>("Root_SUM");
        GameObject.Find("result").transform.Find("Text").GetComponent<Text>().text = "";
        GameObject.Find("bgresult").GetComponent<Image>().color = ColorSpace.pplightgrey;
        GameObject.Find("rootresult").GetComponent<Text>().text = "";
    }

    /* throw away */
    public void _checkround()
    {      
        //somespace
        _resetround();
    }

    /* first transition */
    public void _rootit()
    {
        //reveal the root truth
        reveal = true;

        GameObject.Find("rootbutton").GetComponent<RectTransform>().localPosition = new Vector2{ x = 5000, y = 5000 }; //YEET the object
        GameObject.Find("numberrevealed").GetComponent<RectTransform>().localPosition = _numberrevealedp; //show the next object

        //run through the pawns to reveal their number
        foreach (pawn ppm in ppg.p)
        {
            ppm._pawnobject.transform.Find("icon").transform.Find("pawnnumber").GetComponent<Text>().text = ppm._number.ToString();
        }
    }

    /* second transition */
    public void _sumofall()
    {
        //next sencond step of root truth
        sumresult = 0;
        foreach (pawn ppm in ppg.p)
        {
            sumresult += ppm._number;
        }

        GameObject.Find("sumrevealed").transform.Find("text").GetComponent<Text>().text = "The SUM of all Pawn's number is \n" + sumresult.ToString();
        GameObject.Find("result").GetComponent<Image>().color = ColorSpace.ppwhiteblock;
        GameObject.Find("result").GetComponent<Image>().sprite = Resources.Load<Sprite>("Root");
        GameObject.Find("result").transform.Find("Text").GetComponent<Text>().text = sumresult.ToString();
        GameObject.Find("numberrevealed").GetComponent<RectTransform>().localPosition = new Vector2 { x = 5000, y = 5000 }; //YEET the object
        GameObject.Find("sumrevealed").GetComponent<RectTransform>().localPosition = _numberrevealedp;
    }

    /* third transition */
    public void _rootofsum()
    {
        winner = 0;
        rootresult = 0;
        comparer = new List<float>();
        string structure = "";

        foreach (pawn ppm in ppg.p)
        {
            rootresult += ppm._number;
        }

        structure = "The Square Root of " + rootresult.ToString();

        rootresult = Convert.ToSingle(Math.Round(Mathf.Sqrt(rootresult), 1));

        structure += " is " + rootresult.ToString() + "\n";

        foreach (pawn ppm in ppg.p)
        {
            if (!ppm._eliminated) 
            { 
                comparer.Add(Math.Abs(ppm._number - rootresult)); 
                ppm._root = Math.Abs(ppm._number - rootresult); 
            }
        }

        winner = comparer.Find(x => x == comparer.AsQueryable().Min());
        winners = ppg.p.FindAll(x => x._root == winner);

        if (winners.Count == 1)
        {
            structure += "The Closest one is " + winners[0]._name.ToString();
        }

        if (winners.Count > 1)
        {
            for (int i = 0; i < winners.Count; i++)
            {
                if (i < winners.Count - 1)
                {
                    structure += winners[i]._name + " and ";
                }
                else
                {
                    structure += winners[i]._name;
                }
            }

            structure += " is the closest one \n so this round is a TIE";
        }
        
        GameObject.Find("rootrevealed").transform.Find("text").GetComponent<Text>().text = structure;
        GameObject.Find("result").GetComponent<Image>().color = ColorSpace.ppblacktransparent;
        GameObject.Find("result").transform.Find("Text").GetComponent<Text>().text = "";
        GameObject.Find("bgresult").GetComponent<Image>().color = ColorSpace.pppastellightgreen;
        GameObject.Find("rootresult").GetComponent<Text>().text = Math.Round(rootresult, 1).ToString();
        GameObject.Find("sumrevealed").GetComponent<RectTransform>().localPosition = new Vector2
        {
            x = 5000,
            y = 5000
        };
        GameObject.Find("rootrevealed").GetComponent<RectTransform>().localPosition = _numberrevealedp;
    }

    /* fourth trasition */
    public void _winnerandscore()
    {
        roundcounter += 1;
        //ppg.p[winner]._score += 1;
        //ppg.p[winner]._scoreboard.transform.Find("score").GetComponent<Text>().text = ppg.p[winner]._score.ToString();
        if (winners.Count == 1)
        {
            winners[0]._pawnobject.transform.Find("winner").position = new Vector2
            {
                x = winners[0]._pawnobject.GetComponent<RectTransform>().position.x,
                y = winners[0]._pawnobject.GetComponent<RectTransform>().position.y + 80
            };
        }

        for (int i = 0; i < ppg.pawns; i++)
        {
            if (ppg.p[i]._root != winner && !ppg.p[i]._eliminated)
            {
                ppg.p[i]._score -= 1;
                ppg.p[i]._scoreboard.transform.Find("score").GetComponent<Text>().text = ppg.p[i]._score.ToString();
            }
        }

        foreach (pawn ppm in ppg.p)
        {
            if (ppm._score <= ppg.limits && !ppm._eliminated)
            {
                ppg.eliminiateds += 1;
                ppm._eliminated = true;
                ppm._pawnobject.transform.Find("eliminated").position = new Vector2
                {
                    x = ppm._pawnobject.GetComponent<RectTransform>().position.x,
                    y = ppm._pawnobject.GetComponent<RectTransform>().position.y + 5
                };
                ppm._scoreboard.transform.Find("bgscore").GetComponent<Image>().color = Color.red;
            }
        }

        GameObject.Find("roundtext").GetComponent<Text>().text = "Round " + roundcounter.ToString();
        GameObject.Find("rootrevealed").GetComponent<RectTransform>().localPosition = new Vector2
        {
            x = 5000,
            y = 5000
        };

        if (ppg.eliminiateds >= ppg.pawns - 1)
        {
            GameObject.Find("boardbase").GetComponent<Image>().color = ColorSpace.ppblacktransparent;
            GameObject.Find("ultimatewinner").GetComponent<RectTransform>().localPosition = _ultimatewinnerp;
            GameObject.Find("nextgame").GetComponent<RectTransform>().localPosition = _nextgamep;
            ppg.p.Find(x => x._eliminated == false)._pawnobject.GetComponent<RectTransform>().localPosition = new Vector2
            {
                x = 0,
                y = 0
            };
            ppg.p.Find(x => x._eliminated == false)._pawnobject.GetComponent<RectTransform>().localScale = new Vector2
            {
                x = 4,
                y = 4
            };
            ppg.p.Find(x => x._eliminated == false)._pawnobject.GetComponent<Button>().interactable = true;
            ppg.p.Find(x => x._eliminated == false)._pawnobject.GetComponent<Button>().onClick.RemoveAllListeners();
            foreach (pawn ppm in ppg.p)
            {
                if(ppm._eliminated)
                {
                    ppm._pawnobject.transform.position = new Vector2
                    {
                        x = 5000,
                        y = 5000
                    };
                }
            }
        }
        else
        {
            if (winners.Count == 1)
            {
                GameObject.Find("winnerrevealed").transform.Find("text").GetComponent<Text>().text = winners[0]._name + "\n" + "WIN";
            }
            else
            {
                GameObject.Find("winnerrevealed").GetComponent<Text>().text = "\n" + "TIE";
            }

            GameObject.Find("winnerrevealed").GetComponent<RectTransform>().localPosition = _winnerrevealedp;
            GameObject.Find("nextroundbutton").GetComponent<RectTransform>().localPosition = _nextroundbuttonp;
        }
    }

    /* fifth trasition */
    public void _endgame()
    {

    }

    /* Auto-Generation Component */
    public void _generatepawn()
    {
        ppg = new pawnbox { pawns = _initobjectsqrt.pawncount, limits = _initobjectsqrt.scorelimit, p = new List<pawn>() };
        Transform pawnparent = GameObject.Find("scorebox").transform;

        System.Random rnd = new System.Random();
        List<int> rn = new List<int>();
        while (rn.Count < ppg.pawns)
        {
            int picked = Convert.ToUInt16(rnd.Next(0, 5));
            if (!rn.Exists(x => x == picked))
            {
                rn.Add(picked);
            }
        }

        for (int i = 0; i < ppg.pawns; i++)
        {
            if (i != 0)
            {
                _pawnscore = Instantiate(GameObject.Find("pawnscore0"), GameObject.Find("scorebox").transform);
            }
            else
            {
                _pawnscore = GameObject.Find("pawnscore0");
            }

            _pawnscore.name = "pawnscore" + i.ToString();
            _pawnscore.transform.Find("icon").GetComponent<Image>().sprite = Resources.Load<Sprite>(CharacterSpace.tolist[rn[i]]);

            if (i != 0)
            {
                _pawn = Instantiate(GameObject.Find("pawn0"), GameObject.Find("gameboard").transform);
            }
            else
            {
                _pawn = GameObject.Find("pawn0");
            }
            
            _pawn.name = "pawn" + i.ToString();
            _pawn.transform.Find("pawnname").transform.GetComponent<Text>().text = _pawn.name;
            _pawn.transform.Find("icon").GetComponent<Image>().sprite = Resources.Load<Sprite>(CharacterSpace.tolist[rn[i]]);

            ppg.p.Add(new pawn
            {
                _id = Convert.ToUInt16(i),
                _name = _pawn.name,
                _scoreboard = _pawnscore,
                _pawnobject = _pawn,
                _numberhas = new List<uint>()
            });
        }

        //pawn aligning process
        float angle = 360 / ppg.pawns;
        float revangle = 0;
        foreach(pawn pp in ppg.p)
        {
            pp.ppx = Convert.ToSingle(Math.Cos((revangle * (Math.PI)) / 180)) * 240;
            pp.ppy = Convert.ToSingle(Math.Sin((revangle * (Math.PI)) / 180)) * 240;
            revangle += angle;
            pp._pawnobject.GetComponent<RectTransform>().transform.localPosition = new Vector2
            {
                x = pp.ppx,
                y = pp.ppy
            };
        }
    }

    public void _generatenumberbutton()
    {
        ppnum = new List<numberedbox>();
        GameObject orig = GameObject.Find("box0");
        GameObject numberbox = GameObject.Find("box0");
        int spcing = 10;
        float prevx = numberbox.GetComponent<RectTransform>().transform.localPosition.x - ((numberbox.GetComponent<RectTransform>().rect.width + spcing) * 9);
        float prevy = numberbox.GetComponent<RectTransform>().transform.localPosition.y + (numberbox.GetComponent<RectTransform>().rect.height + spcing);

        for(int i = 0; i <= 100; i++)
        {
            if (i != 0)
            {
                numberbox = Instantiate(GameObject.Find("box0"), GameObject.Find("numberboard").transform);
                numberbox.name = "box" + i.ToString();
                numberbox.transform.Find("Text").transform.GetComponent<Text>().text = i.ToString();
                numberbox.GetComponent<RectTransform>().transform.localPosition = new Vector2
                {
                    x = prevx,
                    y = prevy
                };
            }

            prevx += (numberbox.GetComponent<RectTransform>().rect.width + spcing);
            if (i % 10 == 0)
            {
                prevx = orig.GetComponent<RectTransform>().transform.localPosition.x - ((numberbox.GetComponent<RectTransform>().rect.width + spcing) * 9);
                prevy = numberbox.GetComponent<RectTransform>().transform.localPosition.y - (numberbox.GetComponent<RectTransform>().rect.width + spcing);
            }

            ppnum.Add(new numberedbox
            {
                number = Convert.ToUInt16(i),
                _me = numberbox
            });
        }
    }

    /* Main Calculation */
    public void _hidenumberboard()
    {        
        GameObject.Find("numberboard").transform.localPosition = new Vector2
        {
            x = -5000,
            y = -5000
        };
    }

    public void _shownumberboard()
    {
        _currentpawn = EventSystem.current.currentSelectedGameObject.transform.parent.gameObject;
        if (ppg.p.Find(x => x._pawnobject == _currentpawn)._haspicked) { return; }
        if (ppg.p.Find(x => x._pawnobject == _currentpawn)._numberhas != null)
        {
            for(int i = 0; i <= 100; i++)
            {
                GameObject.Find("box" + i.ToString()).GetComponent<Button>().interactable = true;
            }

            foreach(uint filter in ppg.p.Find(x => x._pawnobject == _currentpawn)._numberhas)
            {
                GameObject.Find("box" + filter.ToString()).GetComponent<Button>().interactable = false;
            }
        }
        
        GameObject.Find("titlenumberboard").GetComponent<Text>().text = _currentpawn.name + "\n" + "is picking number";
        GameObject.Find("locknumber").GetComponent<Button>().interactable = false;
        GameObject.Find("locknumber").GetComponent<Image>().color = ColorSpace.ppwhiteblock;
        GameObject.Find("numberboard").transform.localPosition = new Vector2
        {
            x = 0,
            y = -25
        };

        timer = 30;
        istimerrunning = true;
    }

    public void _selectnumber()
    {
        GameObject current = EventSystem.current.currentSelectedGameObject;
        uint picked = 0;

        //if (ppg.p.Find(x => x._pawnobject == _currentpawn)._haspicked) { return; }
        if (!istimerrunning)
        {
            System.Random rnd = new System.Random();
            picked = Convert.ToUInt16(rnd.Next(0, 100));
        }
        else
        {
            picked = ppnum.Find(x => x._me == current).number;
            GameObject.Find("locknumber").GetComponent<Image>().color = ColorSpace.pppastellightgreen;
            GameObject.Find("locknumber").GetComponent<Button>().interactable = true;
        }
        ppg.p.Find(x => x._pawnobject == _currentpawn)._number = picked;
        List<uint> a = ppg.p.Find(x => x._pawnobject == _currentpawn)._numberhas;
        if (a == null) 
        {
            ppg.p.Find(x => x._pawnobject == _currentpawn)._numberhas = new List<uint> { picked };
        }
        else
        {
            ppg.p.Find(x => x._pawnobject == _currentpawn)._numberhas.Add(picked);
        }
        //haspawnpick = true;
    }

    public void _locknumber()
    {
        if (!istimerrunning && !ppg.p.Find(x => x._pawnobject == _currentpawn)._haspicked)
        {
            _selectnumber();
        }
        //if (!haspawnpick) { return; }
        ppg.p.Find(x => x._pawnobject == _currentpawn)._haspicked = true;

        //haspawnpick = false;
        pawnroundset += 1;
        _currentpawn.transform.Find("icon").GetComponent<Button>().interactable = false;

        _hidenumberboard();
    }
 
    public void _closegame()
    {
        UnityEngine.Object.Destroy(_initobject, 0);
        SceneManager.LoadScene("StartScreen", LoadSceneMode.Single);
        GameObject.Find("Audio Source").GetComponent<AudioSource>().clip = Resources.Load<AudioClip>("Sound/(Start screen&other menu)Routine");
        GameObject.Find("Audio Source").GetComponent<AudioSource>().Play();
    }

    public void _newgame()
    {
        UnityEngine.Object.Destroy(_initobject, 0);
        SceneManager.LoadScene("PreGame", LoadSceneMode.Single);
    }
}