using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;

/// <summary>
/// SliceTeleportシェーダーの中身が複雑なのでその仲介処理を行うC#クラス
/// </summary>
public class SliceTeleportController : MonoBehaviour
{
    [SerializeField]
    private Material originalMaterial;
    [SerializeField]
    private Image target;
    [SerializeField]
    private Canvas canvas;

    private int sliceCount = 4;
    private bool isUseMonoCol = true;
    private Color monoCol = Color.white;

    /// <summary>
    ///GameObjectにアタッチした直後に呼ばれる
    /// </summary>
    private void Reset()
    {
        target = gameObject.GetComponent<Image>();
        if(target == null)
        {
            Debug.LogError("Imageコンポーネントの代入に失敗しました");
        }

        Transform tmpTarget = gameObject.transform;
        canvas = tmpTarget.GetComponent<Canvas>();
        while(canvas == null)
        {
            if(tmpTarget.parent != null)
            {
                tmpTarget = tmpTarget.parent;
            }
            else
            {
                break;
            }
            canvas = tmpTarget.GetComponent<Canvas>();
        }
        if(canvas == null)
        {
            Debug.LogError("Canvasコンポーネントの代入に失敗しました");
        }
    }

    /// <summary>
    /// テレポート処理に必要な座標やスケールの値などをシェーダー側に渡す処理
    /// </summary>
    private void SetBaseMaterialValue()
    {
        target.material = new Material(originalMaterial);
        target.material.SetFloat("_Distance", 1);

        var canvasRect = canvas.GetComponent<RectTransform>();
        target.material.SetFloat("_CanvasScreenHeight", canvasRect.sizeDelta.y);

        var height = canvasRect.sizeDelta.y;
        var inversePoint = canvasRect.InverseTransformPoint(target.transform.position).y;
        var vertY = inversePoint / (height / 2);
        target.material.SetFloat("_PosY", vertY);

        var imageRect = target.GetComponent<RectTransform>();
        target.material.SetFloat("_ImageHeight", imageRect.sizeDelta.y);

        float sumScale = 1;
        Transform scaleTartget = target.transform;
        while(true)
        {
            bool notCanvas = scaleTartget.GetComponent<Canvas>() == null;
            if(scaleTartget.parent != null && notCanvas)
            {
                sumScale *= scaleTartget.transform.localScale.y;
                scaleTartget = scaleTartget.parent.transform;
            }
            else
            {
                break;
            }
        }
        target.material.SetFloat("_ScaleY", sumScale);

        target.material.SetFloat("_UseMonoCol", isUseMonoCol? 1 : 0);
        target.material.SetColor("_MonoCol", monoCol);
        target.material.SetFloat("_SliceCount", sliceCount);
    }

    /// <summary>
    /// テレポートを実行
    /// </summary>
    /// <param name="distance">テレポートの跳躍距離</param>
    /// <param name="duration">テレポートにかかる時間</param>
    public void DoTeleport(float distance, float duration)
    {
        SetBaseMaterialValue();
        target.material.SetFloat("_Distance", distance);
        target.material.SetFloat("_TeleportPow", 0);

        DOTween.To(() => target.material.GetFloat("_TeleportPow"), (val) =>
        {
            target.material.SetFloat("_TeleportPow", val);
        }, 1, duration).SetEase(Ease.InQuad);
    }

    /// <summary>
    /// テレポートの逆再生
    /// </summary>
    /// <param name="distance">テレポートの跳躍距離</param>
    /// <param name="duration">テレポートにかかる時間</param>
    public void UndoTeleport(float distance, float duration)
    {
        SetBaseMaterialValue();
        target.material.SetFloat("_Distance", distance);
        target.material.SetFloat("_TeleportPow", 1);

        DOTween.To(() => target.material.GetFloat("_TeleportPow"), (val) =>
        {
            target.material.SetFloat("_TeleportPow", val);
        }, 0, duration).SetEase(Ease.OutQuad).OnComplete(() =>
        {
            target.material.SetFloat("_Distance", 1);
            target.material.SetFloat("_PosY", 0);
        });
    }
    
    /// <summary>
    /// テレポートする際の単一色の指定
    /// </summary>
    public void SetColor(Color color)
    {
        isUseMonoCol = true;
        monoCol = color;
    }

    /// <summary>
    /// テレポートする際に単一色に変化させない設定
    /// </summary>
    public void UnsetColor()
    {
        isUseMonoCol = false;
    }

    /// <summary>
    /// テレポートする際の画像の分割数を変更する。1~20の指定が可能
    /// </summary>
    public void SetSeliceCount(int sliceCount)
    {
        this.sliceCount = sliceCount;
    }

#if UNITY_EDITOR
    [ContextMenu("DebugDoTeleport")]
    private void DebugDoTeleport()
    {
        DoTeleport(8, 1.5f);
    }

    [ContextMenu("DebugUndoTeleport")]
    private void DebugUndoTeleport()
    {
        UndoTeleport(8, 1.5f);
    }
#endif
}
