using System.Collections;
using System.Collections.Generic;
using UnityEngine.EventSystems;
using UnityEngine;
using UnityEngine.UI;
using System;
using System.Linq;

public class UIManager : MonoBehaviour
{
    [SerializeField]
    Square square;
    [SerializeField]
    Camera playercamera;
    [SerializeField]
    LogScaleSlider velocityslider;
    [SerializeField]
    LogScaleSlider accelslider;
    [SerializeField]
    private Text interactText;

    public Canvas canvas;
    public Text mytime;
    //public Planemovement clock1;
    //public Planemovement clock2;
    //public Text clock1time;
    //public Text clock2time;
    public Text wintext;
    public GameObject _pathUI;
    public LevelManager levelManager;
    public PlayerMovement player;
    public PathRenderer pathRenderer;
    
    private int prevSelectPathNum = -1;
    private Text pathName;
    private Text pathVelocity;
    private Vector3 middlePoint;
    private Vector3 canvasSize;
    private int sliderflag = 0;

    GraphicRaycaster gr;
    PointerEventData ped;

    // Start is called before the first frame update
    void Start()
    {
        _pathUI.SetActive(false);
        pathName = _pathUI.transform.Find("Name").GetComponent<Text>();
        pathVelocity = _pathUI.transform.Find("Velocity").GetComponent<Text>();
        middlePoint = _pathUI.transform.position;
        canvasSize = new Vector3(Screen.width, Screen.height, 0);

        gr = canvas.GetComponent<GraphicRaycaster>();
        ped = new PointerEventData(null);
    }

    // Update is called once per frame
    void Update()
    {
        mytime.text = levelManager.player.time.ToString() + " s";
        //clock1time.text = clock1.GetTime().ToString() + " s";
        //clock2time.text = clock2.GetTime().ToString() + " s";
        if (levelManager.winstate)
        {
            wintext.gameObject.SetActive(true);
        }
        if (Input.GetMouseButtonDown(0))
        {
            ped.position = Input.mousePosition;
            List<RaycastResult> results = new List<RaycastResult>();
            gr.Raycast(ped, results);

            bool isIgnored = true;
            //ui 클릭시.
            foreach (RaycastResult re in results)
            {
                GameObject obj = re.gameObject;
                //panel만 있는지 검사.
                isIgnored &= (obj.tag == "ignored");
                //Debug.Log(obj);
                //슬라이더일때
                if (obj.tag == "VelocitySlider")
                {
                    sliderflag = 1;
                    if (_pathUI.activeSelf == true && prevSelectPathNum != -1)
                    {
                        square.pathVelocity[prevSelectPathNum + 1] = velocityslider.GetLogScaleValue();
                        pathVelocity.text = "Velocity: " + square.GetPathVelocity(prevSelectPathNum).ToString() + "c";
                        break;
                    }
                }
            }

            if (isIgnored)
            {
                //클릭된 ui가 패널만 있을때.
                TryFIndPath();
            }
        }
        else if (sliderflag == 1 && Input.GetMouseButton(0))
        {
            if (_pathUI.activeSelf == true && prevSelectPathNum != -1)
            {
                square.pathVelocity[prevSelectPathNum + 1] = velocityslider.GetLogScaleValue();
                pathVelocity.text = "Velocity: " + square.GetPathVelocity(prevSelectPathNum).ToString() + "c";
            }
        }
        else if (Input.GetMouseButtonDown(1))
        {
            sliderflag = 0;
        }

        //player movement

        if (pathRenderer.pathcreatable)
        {
            if (Input.GetKeyDown("w"))
            {
                var tmp = accelslider.GetLogScaleValue() * (float)Constants.c;
                levelManager.player.alpha += new Vector3(0, 0, tmp);
            }
            else if (Input.GetKeyDown("a"))
            {
                var tmp = accelslider.GetLogScaleValue() * (float)Constants.c;
                levelManager.player.alpha += new Vector3(-tmp, 0, 0);
            }
            else if (Input.GetKeyDown("s"))
            {
                var tmp = accelslider.GetLogScaleValue() * (float)Constants.c;
                levelManager.player.alpha += new Vector3(0, 0, -tmp);
            }
            else if (Input.GetKeyDown("d"))
            {
                var tmp = accelslider.GetLogScaleValue() * (float)Constants.c;
                levelManager.player.alpha += new Vector3(tmp, 0, 0);
            }

            if (Input.GetKeyUp("w"))
            {
                levelManager.player.alpha -= new Vector3(0, 0, levelManager.player.alpha.z);
            }
            else if (Input.GetKeyUp("a"))
            {
                levelManager.player.alpha -= new Vector3(levelManager.player.alpha.x, 0, 0);
            }
            else if (Input.GetKeyUp("s"))
            {
                levelManager.player.alpha -= new Vector3(0, 0, levelManager.player.alpha.z);
            }
            else if (Input.GetKeyUp("d"))
            {
                levelManager.player.alpha -= new Vector3(levelManager.player.alpha.x, 0, 0);
            }
        }

    }

    private Vector3 getMouseClickPosition(RaycastHit hit)
    {
        var point = Camera.main.WorldToScreenPoint(hit.point);
        return point - canvasSize * 0.5f + middlePoint;
    }

    public Vector3 getXYVectorfromXZVector(Vector3 v)
    {
        return new Vector3(v.x, v.z, 0.0f);
    }

    private void updatePathInfo(int pathNum)
    {
        pathName.text = "Path - " + pathNum;
        pathVelocity.text = "Velocity: " + square.GetPathVelocity(pathNum).ToString() + "c";
        velocityslider.UpdateValuebyVelocity(square.GetPathVelocity(pathNum));
    }

    private Vector3 getInnerProduct(Vector3 a, Vector3 b)
    {
        return new Vector3(a.x * b.x, a.y * b.y, a.z * b.z);
    }

    private Vector3 getRatio(Vector3 a, Vector3 b)
    {
        return new Vector3(a.x / b.x, a.y / b.y, 1.0f);
    }

    private void TryFIndPath()
    {
        RaycastHit hit1;
        RaycastHit hit2;
        var ray = Camera.main.ScreenPointToRay(Input.mousePosition);

        if (Physics.Raycast(ray, out hit1))
        {
            ray = playercamera.ViewportPointToRay(hit1.textureCoord);
            if (Physics.Raycast(ray, out hit2))
            {
                var obj = hit2.collider.gameObject;
                if (obj.tag == "path")
                {
                    int pathNum = int.Parse(obj.name.Substring(13));

                    if (pathNum != prevSelectPathNum)
                    {
                        prevSelectPathNum = pathNum;
                        updatePathInfo(pathNum);

                        var mouseClickPosition = getMouseClickPosition(hit1);
                        var tmp = mouseClickPosition - middlePoint;
                        var tmp2 = getXYVectorfromXZVector(hit2.point);
                        var v = square.pathList[pathNum + 1];
                        var k = getRatio(tmp, tmp2);

                        _pathUI.transform.position = getInnerProduct(v, k) + middlePoint;
                        _pathUI.SetActive(true);
                    }
                    else
                    {
                        _pathUI.SetActive(false);
                        prevSelectPathNum = -1;
                        sliderflag = 0;
                    }
                }
                else
                {
                    _pathUI.SetActive(false);
                    prevSelectPathNum = -1;
                    sliderflag = 0;
                }
            }
        }
    }

    /// <summary>
    /// 현재 지정된 path를 시작합니다.
    /// </summary>
    public void PathStart()
    {
        _pathUI.SetActive(false);
        pathRenderer.Background.Toggle = false;
        pathRenderer.pathcreatable = false;
        StartCoroutine(pathRenderer._StartMovingPath(prevSelectPathNum));
        prevSelectPathNum = -1;
    }


    public void PathCancel()
    {
        pathRenderer.DeletePathsAfterNthPath(prevSelectPathNum + 1);
        _pathUI.SetActive(false);
        prevSelectPathNum = -1;
    }

    public void OnDoubleClicked()
    {
        try
        {
            if (levelManager.player.isInertial() && pathRenderer.pathcreatable)
            {
                RaycastHit hit;
                var ray = Camera.main.ScreenPointToRay(Input.mousePosition);

                if (Physics.Raycast(ray, out hit))
                {
                    ray = playercamera.ViewportPointToRay(hit.textureCoord);
                    if (Physics.Raycast(ray, out hit))
                    {
                        levelManager.player.MoveInfinitelyToAbPosition(pathRenderer.transform.InverseTransformPoint(hit.point), velocityslider.GetLogScaleValue());
                        //levelManager.player.MoveToAbPosition(hit.point, velocityslider.GetLogScaleValue());
                        //Debug.Log(velocityslider.GetLogScaleValue() * (float)Constants.c);
                        //Debug.Log(hit.point);
                    }
                }
            }
        }
        catch (Exception e)
        {
            Debug.Log(e);
        }
    }

    public string InteractText
    {
        set
        {
            interactText.text = value;
        }
    }

    public void PopupLastPathUI(int pathNum, RaycastHit hit)
    {
        prevSelectPathNum = pathNum;
        updatePathInfo(pathNum);
        var mouseClickPosition = getMouseClickPosition(hit);
        _pathUI.transform.position = mouseClickPosition;
        _pathUI.SetActive(true);
    }
}
