using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class ChessScript : MonoBehaviour
{
    List<string> code;
    float escdowntime;
    GameObject crosshair;
    public int turn;
    public int immediateturn;
    public string state;
    //float yaw;
    //float pitch;
    Dictionary<int, Vector3> previous_positions;
    Dictionary<int, Quaternion> previous_rotations;
    float timewhenwaitstarted;
    public Vector3 wannaposition;
    public Quaternion wannarotation;
    public GameObject PowerUp;

    public List<AudioClip> playqueue;
    public List<int> priorities;

    public List<AudioClip> nonsense_clips;
    Text instructions;
    public Dictionary<int, bool> isAI;
 
    // Start is called before the first frame update
    void Awake()
    {
        GameObject ai = GameObject.Find("AIWhois");
        if (ai == null)
        {
            isAI = new Dictionary<int, bool>();
            isAI[1] = false;
            isAI[-1] = true;
        }
        else
        {
            isAI = ai.GetComponent<AIWhoisScript>().isAI;
        }

        code = new List<string>();
        instructions = GameObject.Find("Instructions").GetComponent<Text>();
        escdowntime = -1;
        crosshair = transform.Find("CrossHair").gameObject;
        CouldMove(false);
        playqueue = new List<AudioClip>();
        priorities = new List<int>();
        turn = 1;
        immediateturn = 1;
        state = "moving";
        previous_positions = new Dictionary<int, Vector3> ();
        previous_rotations = new Dictionary<int, Quaternion>();
        previous_positions[1] = new Vector3(0, 13, -33.5f);
        previous_rotations[1] = Quaternion.Euler(new Vector3(30, 0, 0));
        //SetCameraTrans(new Vector3(0, 13, -33.5f), Quaternion.Euler(new Vector3(30, 0, 0)));
        previous_positions[-1] = new Vector3(0, 13, 33.5f);
        previous_rotations[-1] = Quaternion.Euler(new Vector3(30, 180, 0));
        CameraBasedOnTurn();
        wannaposition = transform.position;
        wannarotation = transform.rotation;
    }


    public void CheckMate(string player)
    {
        int Atype = Random.Range(0, 3);
        string A = "";
        switch (Atype)
        {
            case 0: A = "A - A textbook checkmate"; break;
            case 1: A = "A - And that is indeed a checkmate"; break;
            case 2: A = "A - Finally we have a checkmate"; break;
        }
        int Btype = Random.Range(0, 4);
        string B = "";
        switch (Btype)
        {
            case 0: B = "B - Amazing"; break;
            case 1: B = "B - Astounding"; break;
            case 2: B = "B - Bringing the match to an end"; break;
            case 3: B = "B - Excellent"; break;
        }
        playqueue.Add(Resources.Load<AudioClip>("Sounds/checkmates/" + A));
        playqueue.Add(Resources.Load<AudioClip>("Sounds/concat/by " + player));
        playqueue.Add(Resources.Load<AudioClip>("Sounds/checkmates/" + B));
        priorities.Add(1);
        priorities.Add(1);
        priorities.Add(1);
        state = "checkmate";
        if (player == "white")
        {
            GameObject.Find("Board").GetComponent<MeshRenderer>().material = Resources.Load<Material>("White");
        }
        else
        {
            GameObject.Find("Board").GetComponent<MeshRenderer>().material = Resources.Load<Material>("Black");
        }
    }
    public void IHaveDied(Piece p)
    { 
        string player = PieceToPlayer(p);
        if (player == "") return;
        
        string type = PieceToType(p);

        if (type == "king")
        {
            CheckMate(p.player == -1 ? "white" : "black");
            return;
        }

        string piecesuffix = Random.Range(0, 2) == 0 ? "1" : "2";
        

        int choice = Random.Range(0, 5);
        string clip = "";
        bool before = false;
        bool doerbefore = false;
        switch (choice)
        {
            case 0: clip = "A swift elimination of-"; before = false; break;
            case 1: clip = "-has fallen off the board"; before = true; break;
            case 2: clip = "-masterfully eliminated there"; before = true; break;
            case 3: clip = "Oh dear there goes-"; before = false; break;
            case 4: clip = "-takes out the opponents-"; before = false; doerbefore = true; break;
        }
        if (doerbefore)
        {
            string elimer = player == "white" ? "black" : "white";
            playqueue.Add(Resources.Load<AudioClip>("Sounds/concat/" + elimer));
            priorities.Add(3);
        }
        if (!before)
        {
            playqueue.Add(Resources.Load<AudioClip>("Sounds/eatings/" + clip));
            priorities.Add(3);
        }
        if (!doerbefore)
        {
            playqueue.Add(Resources.Load<AudioClip>("Sounds/concat/" + player));
            priorities.Add(3);
        }
        playqueue.Add(Resources.Load<AudioClip>("Sounds/nappulat/" + type + piecesuffix));
        priorities.Add(3);
        if (before)
        {
            playqueue.Add(Resources.Load<AudioClip>("Sounds/eatings/" + clip));
            priorities.Add(3);
        }
    }

    public string PieceToxx(Piece p)
    {
        int xx = (int)((p.transform.position.x + 16) / 4);
        string xs = "";
        switch (xx)
        {
            case 0: xs = "a"; break;
            case 1: xs = "b"; break;
            case 2: xs = "c"; break;
            case 3: xs = "d"; break;
            case 4: xs = "e"; break;
            case 5: xs = "f"; break;
            case 6: xs = "g"; break;
            case 7: xs = "h"; break;
        }
        return xs;
    }
    public string PieceToyy(Piece p)
    {
        int yy = (int)((p.transform.position.z + 16) / 4);
        string ys = "";
        switch (yy)
        {
            case 0: ys = "1"; break;
            case 1: ys = "2"; break;
            case 2: ys = "3"; break;
            case 3: ys = "4"; break;
            case 4: ys = "5"; break;
            case 5: ys = "6"; break;
            case 6: ys = "7"; break;
            case 7: ys = "8"; break;
        }
        return ys;
    }
    public string PieceToPlayer(Piece p)
    {
         return p.player == -1 ? "black" : "white";
    }
    public string PieceToType(Piece p)
    {
        return p.PieceType();
    }
    public void IHaveStopped(Piece p)
    {
        //if (playqueue.Count > 0) return;
        string xs = PieceToxx(p);
        string ys = PieceToyy(p);
        
        //print(((p.transform.position.x + 16) / 4).ToString() + " " + ((p.transform.position.z + 16) / 4).ToString());
        if (xs == "" || ys == "") return;

        string player = PieceToPlayer(p);
        string type = PieceToType(p);
        //print(player + " " + type + " " + xs + ys);
        string piecesuffix = Random.Range(0, 2) == 0 ? "1" : "2";
        string xsuffix = Random.Range(0, 3) == 0 ? "1" : (Random.Range(0, 2) == 0 ? "2" : "3");
        string ysuffix = Random.Range(0, 3) == 0 ? "1" : (Random.Range(0, 2) == 0 ? "2" : "3");
        //print("Sounds/nappulat/" + type + piecesuffix + ".mp3");
        playqueue.Add(Resources.Load<AudioClip>("Sounds/nappulat/" + type + piecesuffix));
        playqueue.Add(Resources.Load<AudioClip>("Sounds/ruudut/" + xs + "-" + xsuffix));
        playqueue.Add(Resources.Load<AudioClip>("Sounds/ruudut/" + ys + "-" + ysuffix));
        priorities.Add(2);
        priorities.Add(2);
        priorities.Add(2);
        //GetComponent<AudioSource>().PlayOneShot(play);
    }
    public void PromotionClip(int player)
    {
        //int r = Random.Range(0, 2);
        playqueue.Add(Resources.Load<AudioClip>("Sounds/concat/A_pawn_has_been_promoted_1"));
        priorities.Add(2);
    }

    public void RandomPhrase()
    {
        //if (playqueue.Count > 0) return;
        playqueue.Add(nonsense_clips[Random.Range(0, nonsense_clips.Count)]);
        priorities.Add(5);
    }

    public void CouldMove(bool yes)
    {
        crosshair.GetComponent<SpriteRenderer>().enabled = yes;
    }

    // someone calls this when they take the wheel
    public void Intercepted()
    {
        if (state == "checkmate") return;
        state = "inactive";
    }
    
    float AngleBetweenTwoPoints(Vector3 a, Vector3 b)
    {
        return Mathf.Atan2(a.y - b.y, a.x - b.x) * Mathf.Rad2Deg;
    }
    // called if a piece has moved
    public void NextTurn()
    {
        CouldMove(false);
        if (state == "checkmate") return;
        state = "wait";
        immediateturn = -turn;
        timewhenwaitstarted = Time.time;
        CameraBasedOnTurn();
        RandomPhrase();
    }
    public void ActuallyNextTurn()
    {
        turn = -turn;
        immediateturn = turn;
        CameraBasedOnTurn();
        if (state == "checkmate") return;
        state = "moving";

        if (Random.Range(0, 4) == 0)
        {
            GameObject go = GameObject.Instantiate(PowerUp);
            go.transform.position = new Vector3(Random.Range(-16, 16), 1.5f, Random.Range(-16, 16));
        }
    }

    /*public void SetCameraTrans(Vector3 position, Quaternion rotation)
    {
        wannaposition = position;
        wannarotation = rotation;
    }*/

    public void CameraBasedOnTurn()
    {
        wannaposition = previous_positions[turn];
        wannarotation = previous_rotations[turn];
    }

    // called if the chosen piece decides it'll not be moved
    public void CancelMove()
    {
        if (state == "checkmate") return;
        state = "moving";
        // transform.position = previous_positions[turn];
        CameraBasedOnTurn();
        CouldMove(false);
    }

    private void FixedUpdate()
    {
        transform.position = Vector3.MoveTowards(transform.position, wannaposition, 4f);
        transform.rotation = Quaternion.Lerp(transform.rotation, wannarotation, 0.35f);

        if (state == "moving" || state == "checkmate")
        {
            if (Input.GetKey(KeyCode.W))
            {
                wannaposition += Vector3.forward * turn;
            }
            if (Input.GetKey(KeyCode.S))
            {
                wannaposition += Vector3.back * turn;
            }
            if (Input.GetKey(KeyCode.A))
            {
                wannaposition += Vector3.left * turn;
            }
            if (Input.GetKey(KeyCode.D))
            {
                wannaposition += Vector3.right * turn;
            }
            if (Input.GetKey(KeyCode.Q))
            {
                wannaposition += Vector3.up * turn;
            }
            if (Input.GetKey(KeyCode.E))
            {
                wannaposition += Vector3.down * turn;
            }
        }
        else if (state == "wait")
        {
            if (Input.GetKey(KeyCode.Q) || Input.GetKey(KeyCode.A) ||
                Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.S) ||
                Input.GetKey(KeyCode.E) || Input.GetKey(KeyCode.D))
            {
                ActuallyNextTurn();
            }
            else if (Time.time - timewhenwaitstarted > 2 && turn != immediateturn)
            {
                ActuallyNextTurn();
            }

            instructions.text = "We're just looking at this moving piece now. \n Press any key or wait a few seconds.";
            
        }

        
    }

    void SortQueue()
    {
        // lol
        bool madechange = true;
        int best = 1000;
        while (madechange)
        {
            madechange = false;
            for (int i = 0; i < playqueue.Count - 1; i++) { 
                if (priorities[i] > priorities[i+1])
                {
                    int tempprio = priorities[i];
                    AudioClip tempclip = playqueue[i];
                    priorities[i] = priorities[i + 1];
                    playqueue[i] = playqueue[i + 1];
                    priorities[i + 1] = tempprio;
                    playqueue[i + 1] = tempclip;
                    madechange = true;
                    best = Mathf.Min(best, priorities[i]);
                    best = Mathf.Min(best, priorities[i+1]);
                }
            }
        }
        if (best == 1)
        {
            int i = 0;
            while(i < playqueue.Count)
            {
                if(priorities[i] > 1 && priorities[i] < 5)
                {
                    playqueue.RemoveAt(i);
                    priorities.RemoveAt(i);
                }
                else
                {
                    i += 1;
                }
            }
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (immediateturn == 1)
            instructions.color = new Color32(255, 158, 158, 255);
        if (immediateturn == -1)
            instructions.color = new Color32(141, 255, 149, 255);


        if (!GetComponent<AudioSource>().isPlaying && playqueue.Count > 0)
        {
           
            SortQueue();
            AudioClip curr = playqueue[0];
            if (state != "checkmate" || priorities[0] == 1) 
                GetComponent<AudioSource>().PlayOneShot(curr);
            playqueue.RemoveAt(0);
            priorities.RemoveAt(0);
        }

        if (state == "moving")
        {

            if (!isAI[immediateturn])
                instructions.text = "Use wasdqe to move the camera around. Click on your pieces to move them.";
            else
                instructions.text = "The AI is thinking.";

            previous_positions[turn] = wannaposition;
            previous_rotations[turn] = wannarotation;
            if (!isAI[immediateturn] && Input.GetMouseButtonDown(0))
            {
                RaycastHit raycastHit;
                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                if (Physics.Raycast(ray, out raycastHit, 100f))
                {
                    if (raycastHit.transform != null)
                    {
                        raycastHit.transform.gameObject.SendMessage("Clicked", SendMessageOptions.DontRequireReceiver);
                    }
                }
            }
            if (isAI[immediateturn] && Random.Range(0, 25) == 0)
            {
                Piece p = RandomPiece(immediateturn);
                p.SendMessage("Clicked", SendMessageOptions.DontRequireReceiver);
            }


        }
     

        if (state == "moving") TrackCodes();


        if (Input.GetKeyDown(KeyCode.Escape))
        {
            escdowntime = Time.time;
        }
        if (Input.GetKeyUp(KeyCode.Escape))
        {
            if (escdowntime != -1 && Time.time - escdowntime > 2)
            {
                SceneManager.LoadScene("MenuScene", LoadSceneMode.Single);
                print("load");
            }

            else
            {
                print(Time.time.ToString() + "ddd" + escdowntime.ToString());
                escdowntime = -1;
            }
        }
    }


    // copy paste cuz I have no time
    public void TrackCodes()
    {
        if (Input.GetKeyDown(KeyCode.UpArrow))
        {
            code.Add("up");
        }
        if (Input.GetKeyDown(KeyCode.DownArrow))
        {
            code.Add("down");
        }
        if (Input.GetKeyDown(KeyCode.LeftArrow))
        {
            code.Add("left");
        }
        if (Input.GetKeyDown(KeyCode.RightArrow))
        {
            code.Add("right");
        }
        if (Input.GetKeyDown(KeyCode.A))
        {
            code.Add("A");
        }
        if (Input.GetKeyDown(KeyCode.B))
        {
            code.Add("B");
        }
        string s = "";
        for (int k = 0; k < code.Count; k++)
        {
            s += code[k];
        }
        //print(s);

        List<string> konami = new List<string> { "up", "up", "down", "down", "left", "right", "left", "right", "B", "A" };
        List<string> imanok = new List<string> { "down", "down", "down", "down", "down", "down", "down", "down" };
        List<List<string>> codes = new List<List<string>> { konami, imanok };
        for (int j = 0; j < codes.Count; j++)
        {
            List<string> c = codes[j];
            if (c.Count <= code.Count)
            {
                int startidx = code.Count - c.Count;
                bool ok = true;
                for (int i = 0; i < c.Count; i++)
                {
                    if (code[startidx + i] != c[i])
                    {
                        ok = false;
                    }
                }
                if (ok)
                {
                    ProcessCode(j);
                    code = new List<string>();
                }
            }
        }
    }

    public void ProcessCode(int j)
    {

        if (j == 0)
        {
            Piece[] pieces = GameObject.FindObjectsOfType<Piece>();
            foreach (Piece p in pieces)
            {
                if (p.player == immediateturn) p.power += 1;   
            }
        }
        else if (j == 1)
        {
            Piece[] pieces = GameObject.FindObjectsOfType<Piece>();
            foreach (Piece p in pieces)
            {
                if (p.player == immediateturn) p.power -= 1;
            }
        }
    }

    Piece RandomPiece(int play)
    {
        Piece[] pieces = GameObject.FindObjectsOfType<Piece>();
        List<Piece> owns = new List<Piece>();
        foreach (Piece p in pieces)
        {
            if (p.player == play) owns.Add(p);
        }
        if (owns.Count == 0) return null;
        int r = Random.Range(0, owns.Count);
        return owns[r];
    }
}
