using System.Collections;
using UnityEngine;

using UnityEngine.UI;  // 画像UIの表示制御に使用
using TMPro;  // TextMeshProに使用
using UnityEngine.SceneManagement;  // シーンの切り替えに使用

//////////////////////////////////////////////////////////////////
//【キー操作によるスイング処理、ボールを飛ばす処理、結果表示処理用のクラス】 
// キー操作によるスイングのステップ処理、スイングのパワーと角度を示すゲージUI表示
// パワーと角度から計算した力をボールに加える、ボールとピンまでの距離計算とUI表示
// 結果UI表示、リスタート処理、デバックモード処理
//////////////////////////////////////////////////////////////////
public class SwingController : MonoBehaviour
{
    /////////////////////////////////
    // 【変数の設定】
    /////////////////////////////////

    //【定数の設定】
    const float BASIC_POWER = 755;  // 基準となるボールへの力
    // (パワーゲージ100%、角度ゲージ45°でホールインワンする力)

    //【Unity Editorから設定する変数】
    [SerializeField] GameObject title;  // タイトル画面UI
    [SerializeField] GameObject panel;  // ゲーム画面パネルUI
    [SerializeField] GameObject message;  // ゲーム結果テキストUI

    [SerializeField] GameObject ball;  // ボールのゲームオブジェクト
    [SerializeField] GameObject flag;  // ピンの位置を示すゲームオブジェクト
    [SerializeField] Rigidbody2D rdBody;  // ボールのRigidbody2D

    [SerializeField] Image girl;  // 画面上の女の子の画像
    [SerializeField] Sprite spriteGirl;  // スイング後の女の子の画像

    [SerializeField] Image powerGauge;  // パワーゲージの画像
    [SerializeField] Image angleGauge;  // 角度ゲージの画像
    [SerializeField] Text textLength;  // ピンまでの距離を示すテキストUI

    [SerializeField] Toggle toggle;  // タイトル画面用デバックモード選択トグル

    //【このプログラム内で使用するPrivate変数】
    int swingCount = 0;  // スイング処理のステップカウント

    float swingPower;  // スイングのパワー
    float swingAngle;  // スイングの角度
    float swingTime = 0;  // ゲージ増減用のスイングの経過時間

    bool debugFlag = false;  // デバックモード(ホールインワンのテスト用)


    /////////////////////////////////
    // 【関数の設定】
    /////////////////////////////////

    //【毎フレームに１度動く関数】
    //（Unityの標準関数）
    void Update()
    {
        // スペースキーが押された場合
        if (Input.GetKeyDown(KeyCode.Space))
        {
            // swingCountが0の場合、デバックモードにトグルの値をセット
            if (swingCount == 0) debugFlag = toggle.isOn;

            // スイングのステップを進める関数ClickSwingButtonを呼び出す
            ClickSwingButton();
        }

        // swingCountが1の場合(スイングスタート待ち)
        if (swingCount == 1)
        {
            // タイトル画面UIを無効化
            title.SetActive(false);
            // ゲーム画面パネルUIを有効化
            panel.SetActive(true);
        }

        // swingCountが2の場合(スイングパワー選択待ち)
        else if (swingCount == 2)
        {
            // ゲージ増減用のスイングの経過時間を計測
            swingTime += Time.deltaTime;
            // スイングパワーを0～1.2の間でスイングの経過時間を基に算出
            swingPower = Mathf.PingPong(swingTime, 1.2f);

            // 経過時間を基に算出したスイングパワーをパワーゲージUIに反映
            powerGauge.fillAmount = swingPower / 1.2f;
        }

        // swingCountが3の場合(スイング角度選択待ち)
        else if (swingCount == 3)
        {
            // ゲージ増減用のスイングの経過時間を計測
            swingTime += Time.deltaTime;
            // スイング角度を0～1の間でスイングの経過時間を基に算出
            swingAngle = Mathf.PingPong(swingTime, 1.0f);

            // 経過時間を基に算出したスイング角度を角度ゲージUIに反映
            angleGauge.fillAmount = swingAngle;
        }

        // swingCountが4の場合(スイング後、ボール加速処理)
        else if (swingCount == 4)
        {
            // スイングパワー・角度を基にボールに力をかける関数AddForceBallを呼び出す
            AddForceBall();

            // 女の子の画像をスイング後の画像に切り替える
            girl.sprite = spriteGirl;
            // スイング処理のステップカウントをカウントアップ
            swingCount++;
        }

        // swingCountが5の場合(ボール飛行状態、ボール停止待ち)
        else if (swingCount == 5)
        {
            // ボールとピンまでの距離を測定
            float dist =
                Vector2.Distance(ball.transform.position, flag.transform.position);
            // 初期位置がピンまで100m想定で、ピンまでの距離をメートル換算
            int disInt = Mathf.FloorToInt(dist * 100 / 15f);

            // ピンまで距離をテキストUIに表示
            textLength.text = disInt.ToString();

            // ボールのX方向の速度が０かつボールの位置が初期位置より前にある場合
            // 又は、ボールが画面外のOBエリアにある場合
            if ((rdBody.linearVelocityX == 0 && ball.transform.position.x > -9)
                || ball.transform.position.x > 9)
            {
                // コルーチン関数FinishGameを呼び出す
                StartCoroutine(FinishGame(disInt));
            }
        }

        // swingCountが6の場合(ゲーム終了、再実行指示待ち)
        else if (swingCount == 6)
        {
            // シーン「GameMain」を呼び出す
            SceneManager.LoadScene("GameMain");
        }
    }


    //【スイングパワー・角度を基にボールに力をかける関数】
    void AddForceBall()
    {
        // スイング角度0～1を実際の角度15°～75°に換算
        float angleDeg = Mathf.Lerp(15f, 75f, swingAngle);

        // デバックモードの場合
        if (debugFlag)
        {
            // ホールインワンする力のパワー100%、角度45°を代入
            swingPower = 1; angleDeg = 45;
        }

        // スイング角度からX,Y方向の方向ベクトルを計算
        float dx = Mathf.Cos(angleDeg * Mathf.Deg2Rad);
        float dy = Mathf.Sin(angleDeg * Mathf.Deg2Rad);
        // X,Y方向の方向ベクトルから正規化した方向ベクトルを計算
        float xRate = Mathf.Abs(dx) / (Mathf.Abs(dx) + Mathf.Abs(dy));
        float yRate = Mathf.Abs(dy) / (Mathf.Abs(dx) + Mathf.Abs(dy));

        // 基準となる力を基にスイングパワーの割合での力を計算
        float power = swingPower * BASIC_POWER;

        // ボールを有効化
        ball.SetActive(true);
        // ボールにスイングパワーとスイング角度から計算した力をかける
        rdBody.AddForce(new Vector2(power * xRate, power * yRate));
    }


    //【ボールが停止してゲーム終了処理を行うコルーチン】
    IEnumerator FinishGame(int disInt)
    {
        // 指定秒待つ
        yield return new WaitForSeconds(1.5f);

        // ゲーム結果テキストUIを有効化
        message.SetActive(true);
        // ボールのゲームオブジェクトを無効化
        ball.SetActive(false);

        // ボールのピンまでの距離が0でない場合
        if (disInt != 0)
        {
            // ゲーム結果のテキストを変更(初期値:Hole in One!!)
            message.GetComponent<TextMeshProUGUI>().text
                = "<color=red><size=60%>Too bad! Try again!</size></color>";
        }
    }


    //【スイング処理のステップを進める関数】
    public void ClickSwingButton()
    {
        // スイング処理のステップカウントをカウントアップ
        swingCount++;
        // スイングの経過時間をゼロリセット
        swingTime = 0;
    }
}
