using Cinemachine;
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.SceneManagement;

public class GameApp : MonoBehaviour
{
    public static GameApp Instance;

    [SerializeField] private float defultSpawnTimerMax = 1f;
    [SerializeField] private float playerDestroyAniTimerMax = 1f;
    [SerializeField] private float Height = 1000f;
    [SerializeField] private float ChangeHeight = 500f;
    [SerializeField] private Transform playerPref;
    [SerializeField] private Cinemachine.CinemachineVirtualCamera cinemachine;
    [SerializeField] private float defaultAwayTimerMax = 5f;
    [SerializeField] private float spawnMinRate = 1.1f;
    [SerializeField] private float spawnMaxRate = 1.5f;
    public Transform gameStartPoint;
    public GameStartUI gameStartUI;


    private Player player;
    [SerializeField] private List<Creature> deepCreatureList;
    [SerializeField] private List<Creature> middleCreatureList;
    [SerializeField] private List<Creature> upCreatureList;
    
    private List<Creature> currentCreatureList;

    private float cameraAwayTimer;
    private float currentHeight;
    private float spawnTimer;
    private float awayTimer = 3f;

    private bool needAway = false;
    private float orginalOrthValue;
    private float targetOrthValue;

    private float sceneCurrentHeight = 1080f;
    private float sceneCurrentLength = 1920f;

    private bool isGamePause;

    private bool paopaoGoingBreak;
    private float playerDestroyAniTimer;

    private bool hasPlayer;
    private bool startUp;
    private bool startSpawn;
    private bool detRestart;
    public Transform reStartText;

    private void Awake()
    {
        Instance = this;
        currentCreatureList = new List<Creature>();
    }

    private void Start()
    {
        currentHeight = Height;
        spawnTimer = defultSpawnTimerMax;

        currentCreatureList = deepCreatureList;
        playerDestroyAniTimer = playerDestroyAniTimerMax;
    }

    private void Update()
    {
        if(startUp)
        {
            HandleUpLogic();
        }

        HandleMaxHeightLogic();

        if (startSpawn)
        {
            HandleSpawnCreature();
        }

        HandleCremaAwayContinuely(orginalOrthValue, targetOrthValue);
        HandlePaopaoBreak();

        if (detRestart)
        {
            if (Input.GetKeyDown(KeyCode.Mouse0))
            {
                string currentSceneName = SceneManager.GetActiveScene().name;

                // 重新加载当前场景
                SceneManager.LoadScene(currentSceneName);
            }
        }
    }

    private void HandlePaopaoBreak()
    {
        if(paopaoGoingBreak)
        {
            playerDestroyAniTimer -= Time.deltaTime;
            if(playerDestroyAniTimer < 0)
            {
                Transform transform = Instantiate(reStartText);
                transform.position = player.transform.position;
                cinemachine.Follow = transform;
                cinemachine.LookAt = transform;
                detRestart = true;
                player.Hide();
            }
        }
    }

    private void HandleCremaAwayContinuely(float orginOrthValue,float targetOrthValue)
    {
        if(!needAway)
        {
            return;
        }

        cameraAwayTimer -= Time.deltaTime;
        if(cameraAwayTimer < 0)
        {
            needAway = false;
            SetCinemachineOrthValue(targetOrthValue);
        }
        else
        {
            float value = targetOrthValue - (targetOrthValue - orginOrthValue) * (cameraAwayTimer / defaultAwayTimerMax);
            SetCinemachineOrthValue(value);
        }
        
    }

    private void HandleMaxHeightLogic()
    {
        if(currentHeight <= 0)
        {
            Debug.Log("GameOver:Height0");
            HeightTo0Logic();
        }
    }

    private void HeightTo0Logic()
    {
        Debug.Log("Height:0Over");
    }

    private void HandleUpLogic()
    {
        if(hasPlayer)
        {
            float upSpeed = player.GetCurrentUpSpeed();
            currentHeight -= upSpeed * Time.deltaTime;
        }
    }

    public float GetCurrentHeight()
    {
        return currentHeight;
    }

    public void HandleSpawnCreature()
    {
        spawnTimer -= Time.deltaTime;
        if(spawnTimer < 0)
        {
            Vector3 spawnPos = GetSpawnPos();
            int listLen = currentCreatureList.Count;
            int index = RandomSpawnNum(listLen);
            Transform spawnedObject = Instantiate(currentCreatureList[index].transform);
            spawnedObject.transform.position = spawnPos;
            spawnTimer = defultSpawnTimerMax;
            //Debug.Log("Spawn");
        }
    }

    private Vector3 GetSpawnPos()
    {
        System.Random random = new System.Random();
        Vector3 playerPos = player.transform.position;
        float playerX = playerPos.x;
        float playerY = playerPos.y;
        bool posX = random.Next(2) == 0 ? false : true;
        bool posY = random.Next(2) == 0 ? false : true;
        float randomX = random.Next((int)(sceneCurrentLength * spawnMaxRate / 2f));
        float randomY;
        bool needmoreY;
        if(randomX < sceneCurrentLength * spawnMinRate / 2f)
        {
            needmoreY = false;
        }
        else
        {
            needmoreY = true;
        }

        if(needmoreY)
        {
            randomY = random.Next((int)(sceneCurrentHeight * spawnMaxRate / 2f));
        }
        else
        {
            randomY = random.Next((int)(sceneCurrentHeight * spawnMinRate / 2f),(int)(sceneCurrentLength * spawnMaxRate / 2f));
        }
        
        
        if(posX)
        {
            playerX += randomX;
        }
        else
        {
            playerX -= randomX;
        }
        if (posY)
        {
            playerY += randomY;
        }
        else
        {
            playerY -= randomY;
        }


        return new Vector3(playerX, playerY, 0);
    }

    private float HandleCremaAway(float multi)
    {
        sceneCurrentHeight *= multi;
        sceneCurrentLength *= multi;

        float curSize = cinemachine.m_Lens.OrthographicSize;
        float newSize = curSize * multi;
        return newSize;
    }

    private void SetCinemachineOrthValue(float value)
    {
        cinemachine.m_Lens.OrthographicSize = value;
    }

    public Vector3 getRandomDir()
    {
        System.Random random = new System.Random();
        float randomX = (float)random.NextDouble();
        float randomY = (float)random.NextDouble();
        bool posX = random.Next(2) == 0 ? false : true;
        bool posY = random.Next(2) == 0 ? false : true;

        if (!posX)
        {
            randomX = -randomX;
        }
        if (!posY)
        {
            randomY = -randomY;
        }

        Vector3 result = new Vector3();
        result.x = randomX;
        result.y = randomY;
        return result;
    }

    public float GetPlayerDistance(Vector3 pos)
    {
        Vector3 distanceVec = player.transform.position - pos;
        return distanceVec.magnitude;
    }

    public int RandomSpawnNum(int maxValue)
    {
        System.Random random = new System.Random();
        int value = random.Next(maxValue);
        return value;
    }

    public bool GetRandomBool()
    {
        System.Random random = new System.Random();
        return random.Next(2) == 0 ? false : true;
    }

    public void HandlePlayerDestroyedLogic()
    {
        paopaoGoingBreak = true;

    }

    private void PauseGame()
    {
        Time.timeScale = 0f;
        isGamePause = true;
    }

    internal void SpawnPlayerAwayCamera()
    {
        Transform transform = Instantiate(playerPref);
        player = transform.GetComponent<Player>();
        transform.position = gameStartPoint.position;
        cinemachine.Follow = transform;
        cinemachine.LookAt = transform;

        startUp = true;
        startSpawn = true;
        hasPlayer = true;

        orginalOrthValue = cinemachine.m_Lens.OrthographicSize;
        targetOrthValue = HandleCremaAway(3f);
        cameraAwayTimer = defaultAwayTimerMax;
        needAway = true;

        gameStartUI.Hide();
    }
}
