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]
    PathRenderer pathrenderer;
    [SerializeField]
    Camera playercamera;
    [SerializeField]
    LogScaleSlider velocityslider;
    [SerializeField]
    LogScaleSlider accelslider;


    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 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))
        {
            _pathUI.SetActive(false);
            prevSelectPathNum = -1;
            sliderflag = 0;
        }

        //player movement

        if(Input.GetKeyDown("w"))
        {
            var tmp = accelslider.GetLogScaleValue();
            levelManager.player.alpha += new Vector3(0, 0, tmp);
        }
        else if(Input.GetKeyDown("a"))
        {
            var tmp = accelslider.GetLogScaleValue();
            levelManager.player.alpha += new Vector3(-tmp, 0, 0);
        }
        else if(Input.GetKeyDown("s"))
        {
            var tmp = accelslider.GetLogScaleValue();
            levelManager.player.alpha += new Vector3(0, 0, -tmp);
        }
        else if(Input.GetKeyDown("d"))
        {
            var tmp = accelslider.GetLogScaleValue();
            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 tmp = Camera.main.WorldToScreenPoint(hit.point);
        return tmp - canvasSize * 0.5f + middlePoint;
    }

    private Vector3 getDestVector(Vector3 hitVector1, Vector3 hitVector2, int pathNum)
    {
        hitVector1.z = 0;
        var v = square.GetDestPoint(pathNum) - hitVector2;
        var k = hitVector1.magnitude / hitVector2.magnitude;

        return k * v;
    }

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

    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;
                Debug.Log(obj.tag);
                if (obj.tag == "path")
                {
                    int pathNum = int.Parse(obj.name.Substring(13));

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

                        var mouseClickPosition = getMouseClickPosition(hit1);
                        var v = getDestVector(mouseClickPosition - middlePoint, new Vector3(hit2.point.x, hit2.point.z, 0.0f), pathNum);

                        _pathUI.transform.position = mouseClickPosition + v;
                        _pathUI.SetActive(true);

                        prevSelectPathNum = pathNum;
                    }
                    else
                    {
                        _pathUI.SetActive(false);
                        prevSelectPathNum = -1;
                        sliderflag = 0;
                    }
                }
                else
                {
                    _pathUI.SetActive(false);
                    prevSelectPathNum = -1;
                    sliderflag = 0;
                }
            }
        }
    }

    /// <summary>
    /// 현재 지정된 path를 시작합니다.
    /// </summary>
    public void PathStart()
    {
        bool result;
        var positions = pathRenderer.PathPositionsXZ;
        var velocitys = pathRenderer.PathVelocitys;

        if (positions.Count <= 1 || velocitys.Count <= 1)
        {
            return;
        }
        // remove dummy
        positions.RemoveAt(0);
        velocitys.RemoveAt(0);

        result = levelManager.player.MoveToRetivePosition(positions, velocitys);

        if (result)
        {
            pathRenderer.PathClear();
        }
    }

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

    public void OnDoubleClicked()
    {
        try
        {
            if (levelManager.player.isInertial())
            {
                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(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);
        }
    }
}
