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

public class Laser : MonoBehaviour
{
    public GameObject Bullet;
    public float BulletSpeed = 10.0f;

    public Material ColorWheelMaterial;
    public Material LaserMaterial;
    public float LaserWidth = 0.05f;
    private List<GameObject> _cylinders = new List<GameObject>();
    private List<GameObject> _spheres = new List<GameObject>();
    private Beacon _targetBeaconRef = null;

    private Queue<Vector3> _activeTransforms = new Queue<Vector3>();
    private int _layerMirror;
    public LayerMask _layerWall;
    private int _layerEndPoint;
    private int _layerButton;

	private float _cylinderLength = 0.5f;

    private int _cylinderIndex;
    private int _sphereIndex;

    private AudioSource _source;
    public ColourSampler ColourSampler;

    private void Start()
    {
        _layerMirror = LayerMask.NameToLayer("Mirror") ;
        //_layerWall = LayerMask.NameToLayer("Default");
        _layerEndPoint = LayerMask.NameToLayer("EndPoint");
		_layerButton = LayerMask.NameToLayer("Button");

		GameObject parent = new GameObject("TMP");
        for (int i = 0; i < 30; i++)
        {
            _spheres.Add(GameObject.CreatePrimitive(PrimitiveType.Sphere));
            _spheres.Last().SetActive(false);
            _spheres.Last().transform.parent = parent.transform;
            Destroy(_spheres.Last().GetComponent<Collider>());
            _cylinders.Add(GameObject.CreatePrimitive(PrimitiveType.Cylinder));
            _cylinders.Last().SetActive(false);
            _cylinders.Last().transform.parent = parent.transform;
            Destroy(_cylinders.Last().GetComponent<Collider>());
        }

        _source = GetComponent<AudioSource>();
    }

    public void SetSoundActive(bool b)
    {
        if (b)
            _source.Play();
        else
           _source.Stop(); 
    }
    public void Predict(Vector3 pos, Vector3 direc, int colorNumber)
    {
        ResetLaser();
        _cylinderIndex = 0;
        _sphereIndex = 0;
        // Reset our target reference
        _targetBeaconRef = null;
        CheckForNextPoint(pos, direc, colorNumber);

    }

    public void ResetLaser()
    {
        while (_cylinderIndex > 0)
        {
            _cylinders[_cylinderIndex - 1].SetActive(false);
            _cylinderIndex--;
        }
        while (_sphereIndex > 0)
        {
            _spheres[_sphereIndex - 1].SetActive(false);
            _sphereIndex--;
        }

        _activeTransforms.Clear();
    }

    private void MakeBeam(Vector3 beginPos, Vector3 endPos, int colorNumber)
    {
        GameObject cyl = _cylinders[_cylinderIndex];
        cyl.SetActive(true);
        cyl.transform.position = (beginPos + endPos) / 2;
        cyl.transform.LookAt(endPos);
        Vector3 angle = cyl.transform.localEulerAngles;
        cyl.transform.localEulerAngles = new Vector3(angle.x + 90, angle.y, angle.z);
        cyl.transform.localScale = new Vector3(LaserWidth, (endPos - beginPos).magnitude * _cylinderLength, LaserWidth);
        Renderer r = cyl.GetComponent<Renderer>();
        r.material = LaserMaterial;
        Color col;
        if (!ColourSampler)
        {
            Debug.LogError("No ColourPicker in Laser");
            col = Color.magenta;
        }
        col = ColourSampler.GetColor(colorNumber);
        r.material.color = col;
        //cyl.GetComponent<Renderer>().material.SetColor("_EmissionColor", _colourSampler.GetColor(colorNumber));
        _cylinderIndex++;

        GameObject sphere = _spheres[_sphereIndex];
        sphere.SetActive(true);
        sphere.transform.position = endPos;
        sphere.transform.localScale = new Vector3(LaserWidth * 3, LaserWidth * 3, LaserWidth * 3);
        r = sphere.GetComponent<Renderer>();
        r.material = LaserMaterial;
        r.material.color = col;
        //sphere.GetComponent<Renderer>().material.SetColor("_EmissionColor", _colourSampler.GetColor(colorNumber));
        _sphereIndex++;
        
        _activeTransforms.Enqueue(sphere.transform.position);
    }

    private void CheckForNextPoint(Vector3 pos, Vector3 direc, int colorNumber)
    {
        RaycastHit hit;
        if (Physics.Raycast(pos, direc, out hit, 100.0f))
        {
            int layerHit = hit.transform.gameObject.layer;

            if (((0x1 << layerHit ) &_layerWall) != 0)
            {
                MakeBeam(pos, hit.point, colorNumber);
                return;
            }

            if (layerHit == _layerMirror)
            {
                MakeBeam(pos, hit.point, colorNumber);

                Vector3 normal = hit.normal;
                float dot = Vector3.Dot(direc, normal);
                Vector3 reflectedDirec = direc - 2 * dot * normal;

                MirrorMovement mm = hit.transform.GetComponent<MirrorMovement>();
                if (mm != null )
                    colorNumber += mm.EnhanceAmount;
                if (colorNumber < 0)
                    colorNumber = 0;
                if (colorNumber > ColourSampler.steps - 1)
                    colorNumber = ColourSampler.steps - 1;

                CheckForNextPoint(hit.point, reflectedDirec, colorNumber);
                return;
            }

            if (layerHit == _layerEndPoint)
            {
                MakeBeam(pos, hit.point, colorNumber);

                //Endpoint logic
                _targetBeaconRef = hit.collider.gameObject.GetComponent<Beacon>();
				if(_targetBeaconRef != null)
					_targetBeaconRef.ToggleActivate(colorNumber);
                return;
            }
			if (layerHit == _layerButton)
			{
				MakeBeam(pos, hit.point, colorNumber);

				//Endpoint logic

				return;
			}
		}
        MakeBeam(pos, pos + direc * 100.0f, colorNumber);
    }

    //public void Testbutton()
    //{
    //    Debug.Log("Destroy the universe");
    //}

    //public void Fire()
    //{
    //    if (_targetBeaconRef != null && !_targetBeaconRef.IsActivated)
    //    {
    //        _targetBeaconRef.ToggleActivate(0);
    //       // GameObject bullet = Instantiate(Bullet, transform.position, transform.rotation);
    //       // Bullet b = bullet.GetComponent<Bullet>();
    //       // b.BulletSpeed = BulletSpeed;
    //       // b.BulletTransforms = new Queue<Vector3>(_activeTransforms);
    //       // b.BeaconRef = _targetBeaconRef;
    //    }
    //}
}