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


public abstract class NoteObject : MonoBehaviour
{
    public static Action<JudgeResult> OnNoteHit;
    protected float remainedTime;

    public Vector3 startPoint { get { return endPoint + new Vector3(0, 0, 50); } }
    public Vector3 endPoint;

	public float maxRemainedTime = 5;
	public float perfectZ = 50;

    public AudioClip[] hitSfx;

    protected virtual void OnDestroy()
    {
        
    }

    public void Awake()
    {
        remainedTime = maxRemainedTime;
    }

    public virtual void NoteHit(JudgeResult judge)
    {
        AudioClip hitClip = null;
        // play hit sound
        if (judge.type == JudgeType.Perfect)
            hitClip = hitSfx[0];
        if (judge.type == JudgeType.Hit)
            hitClip = hitSfx[1];

        if (hitClip)
        {
            AudioSource.PlayClipAtPoint(hitClip, Vector3.zero);
        }

        GameObject hitEffect = null;
        // hit effect

        if (judge.type == JudgeType.Perfect)
            hitEffect = PlayEngine.inst.hitEffectPrefabs[0];
        if (judge.type == JudgeType.Hit)
            hitEffect = PlayEngine.inst.hitEffectPrefabs[1];
        if (judge.type == JudgeType.Miss)
            hitEffect = PlayEngine.inst.hitEffectPrefabs[2];
        OnNoteHit?.Invoke(judge);

        if (hitEffect && judge.type != JudgeType.Ignore)
        {
            // show explosion effect
            Instantiate(hitEffect, transform.position, Quaternion.identity);

            // TODO: temporary implementation
            // make note invisible

            StartCoroutine(DissolveRoutine());

            /*
            var meshRenderer = gameObject.GetComponent<MeshRenderer>();
            if (meshRenderer) meshRenderer.enabled = false;
            */

            var trailRenderer = gameObject.GetComponent<TrailRenderer>();
            if (trailRenderer) trailRenderer.enabled = false;
            

            PlayEngine.inst.HandleNoteJudge(judge.type);
        }
    }

    public virtual void SetPosition(float remainedTime)
    {
        float z = 250 * remainedTime;
        float t = Mathf.Pow(1 - z / 250, 3);
        transform.position = new Vector3(t * endPoint.x, t * endPoint.y, endPoint.z + z);
    }

    public abstract bool IsHit(Ray ray);

    private IEnumerator DissolveRoutine()
    {
        Material mat = new Material(Shader.Find("Unlit/Dissolve"));
        MeshRenderer mr = GetComponent<MeshRenderer>();
        mat.SetColor("_Color", mr.material.color);
        mat.SetColor("_Glow", (Color.white + mr.material.color) / 2);
        mr.material = mat;

        Texture2D noise = new Texture2D(100, 100);

        float scale = UnityEngine.Random.Range(20, 50);
        for (int i = 0; i < noise.width; ++i)
        {
            for (int j = 0; j < noise.height; ++j)
            {
                float noiseVal = Mathf.PerlinNoise(scale * i / noise.width, scale * j / noise.height);
                noise.SetPixel(i, j, new Color(noiseVal, noiseVal, noiseVal, 1));
            }
        }
        noise.Apply();
        mat.SetTexture("_NoiseTex", noise);

        const float time = 0.5f;

        for (float t = 0; t < time; t += Time.deltaTime)
        {
            //print(t / time);
            mat.SetFloat("_Threshold", t / time);
            yield return null;
        }
        mat.SetFloat("_Threshold", 1);

    }
}
