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

public class WaveVisualiser : MonoBehaviour
{
    static public int TextureDimension = 1024;

    public ColourSampler colSampler;
    public Texture2D MaskedAlphaSineTiled;
    public float speed = 1.0f;
    public float lerpSpeed = 2.5f;
    //public float stepWidth = 0.15f;

    private const float minSpeed = 1.0f;
    private const float maxSpeed = 15.0f;

    public List<Transform> genParents = null;
    private float ctr = 0.0f;

    private Material AnimMat = null;
    private List<Mesh> AnimMeshes = new List<Mesh>();
    //private Mesh AnimMesh = null;

    private bool transformationReady = true;

    private void Awake()
    {
        // create 3 for now, 1 back, 2 sides
        foreach (Transform t in genParents)
        {
            CreatePlane(t);
        }

        // "scale speed"
        lerpSpeed *= 0.01f;
    }

    private void Start()
    {
        AnimMat.color = colSampler.GetColor(0); //default start colour, has offset of 1 for some reason. no time
        var gv = GetComponent<GunColorWheelVisualizer>();
        gv.SetColor(AnimMat.color);
    }

    public void IncreaseFrequency(Gun g)
    {
        if (transformationReady && g.StartColor + 1 < colSampler.steps)
        {
            transformationReady = false; //gets reset at end of coroutine
            StartCoroutine(smoothIncreaseFreq(g));
        }
    }

    private IEnumerator smoothIncreaseFreq(Gun g)
    {
        float stepWidth = (maxSpeed / colSampler.steps);
            var uvs = AnimMeshes.First().uv;

            float target = (uvs[0].x - stepWidth * 2);
            float spTarget = speed + stepWidth;

            var colorRange = colSampler.GetColorRange(g.StartColor);

            // Warning: cheap ass no brain code
            var gv = GetComponent<GunColorWheelVisualizer>();
            while (uvs[0].x > target) //too lazy for double check
            {
                uvs[0].x -= lerpSpeed;
                uvs[3].x -= lerpSpeed;

                if (speed < spTarget)
                {
                    speed += lerpSpeed;
                }

                if (colorRange.Any())
                {
                    AnimMat.color = colorRange.Dequeue();
                    gv.SetColor(AnimMat.color);

                }
                foreach (Mesh m in AnimMeshes)
                {
                    m.uv = uvs;
                }
            yield return new WaitForFixedUpdate(); // only do this after all 3 have changed
        }
        transformationReady = true;
        g.StartColor++;
    }

    public void DecreaseFrequency(Gun g)
    {
        if (transformationReady && g.StartColor > 0)
        {
            transformationReady = false; //gets reset at end of coroutine
            StartCoroutine(smoothDecreaseFreq(g));
        }
    }

    private IEnumerator smoothDecreaseFreq(Gun g)
    {
        float stepWidth = (maxSpeed / colSampler.steps);
        var uvs = AnimMeshes.First().uv;

        float target = uvs[0].x + stepWidth * 2;
        float spTarget = speed - stepWidth;

        var colorRange = colSampler.GetColorRangeReversed(g.StartColor - 1);

        var gv = GetComponent<GunColorWheelVisualizer>();
        while (uvs[0].x < target)
        {
            uvs[0].x += lerpSpeed;
            uvs[3].x += lerpSpeed;

            if (speed > spTarget)
            {
                speed -= lerpSpeed;
            }

            if (colorRange.Any())
            {
                AnimMat.color = colorRange.Dequeue();
                gv.SetColor(AnimMat.color);
            }

            foreach (Mesh m in AnimMeshes)
            {
                m.uv = uvs;
            }
            yield return new WaitForFixedUpdate();
        }
        transformationReady = true;
        g.StartColor--;
    }

    private void Update()
    {
        // Make wave move
        ctr += Time.deltaTime * speed;
        AnimMat.SetTextureOffset("_MainTex", new Vector2(ctr, 0.0f));
    }

    private void CreatePlane(Transform genParent)
    {
        GameObject plane = new GameObject("Plane");
        MeshFilter meshFilter = (MeshFilter)plane.AddComponent(typeof(MeshFilter));
        meshFilter.mesh = CreateMesh(1, 0.2f);
        MeshRenderer renderer = plane.AddComponent(typeof(MeshRenderer)) as MeshRenderer;

        if (AnimMat == null) // make only first time
        {
            AnimMat = new Material(Shader.Find("Custom/Additive"));
            AnimMat.SetFloat("_Strength", 6);
            AnimMat.mainTexture = MaskedAlphaSineTiled;
        }

        renderer.material = AnimMat;

        //renderer.material.shader = Shader.Find("Custom/Additive");
        //renderer.material.SetFloat("_Strength", 6);

        //renderer.material.mainTexture = MaskedAlphaSineTiled;

        // Parent
        if (genParent != null)
        {
            plane.transform.position = genParent.position;
            plane.transform.rotation = genParent.rotation;
            plane.transform.parent = genParent.transform;
            plane.transform.localScale = Vector3.one;
        }
    }

    private Mesh CreateMesh(float width, float height)
    {
        Mesh m = new Mesh();
        m.name = "ScriptedMesh";
        m.vertices = new Vector3[] {
         new Vector3(-width, -height, 0.01f),
         new Vector3(width, -height, 0.01f),
         new Vector3(width, height, 0.01f),
         new Vector3(-width, height, 0.01f)
     };
        m.uv = new Vector2[] {
         new Vector2(1, 1),
         new Vector2 (0, 1),
         new Vector2 (0, 0),
         new Vector2 (1, 0)
     };
        m.triangles = new int[] { 0, 1, 2, 0, 2, 3 };
        m.RecalculateNormals();

        AnimMeshes.Add(m);
        //AnimMesh = m; //save for later
        return m;
    }
}