using System;
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Rendering.PostProcessing;

public class PlayerController : OrbitalBehaviour
{
    [Header("References")]
    [SerializeField] private MeshRenderer m_Renderer;
    [SerializeField] private Text m_ScoreText;
    [SerializeField] private Text m_ModifierText;
    [SerializeField] private Material m_DefaultMaterial;
    [SerializeField] private Material m_FreeHitMaterial;
    [SerializeField] private PostProcessVolume m_PostProcessVolume;
    
    private static PlayerController Instance;

    private static int s_HighScore = 20;
    public static int s_PlayerScore;
    
    private Vector3 m_SuicidePoint;
    private float m_DeathLerp;

    private bool m_HasFreeHitActive;
    private bool m_HasInvincibility;
    private bool m_KillingItself;

    private void Start()
    {
        s_HighScore = Mathf.Max(s_HighScore, PlayerPrefs.GetInt("HighScore", 0));
        Instance = this;
        
        BehaviourManager.SetPlayer(this);
        RegisterObject(new OrbitalInitializer
        {
            ObjectRadius = 0.1f,
            SpinSpeed = 0.2f
        });

        IsAttachedToRings = true;
    }

    private void UpdateUI()
    {
        m_ScoreText.text = s_PlayerScore.ToString();
        
        m_ScoreText.color = s_PlayerScore > s_HighScore ? Color.yellow : Color.white;
        m_Renderer.material = m_HasFreeHitActive ? m_FreeHitMaterial : m_DefaultMaterial;
    }

    private void UpdatePlayerInput()
    {
        if (GlobalInput.IsScreenClicked && BehaviourManager.AllowPlayerInput)
        {
            AdvanceRing();
        }
    }

    private void UpdateDeathState()
    {
        if (!m_KillingItself)
            return;
        
        transform.position = Vector3.Lerp(m_SuicidePoint, m_SuicidePoint.normalized * 20f, m_DeathLerp);
        m_DeathLerp += Time.deltaTime;
    }

    public void Update()
    {
        UpdateUI();
        UpdatePlayerInput();
        UpdateDeathState();
    }

    private IEnumerator OnGrowPlayerModifier()
    {
        transform.localScale *= 1.5f;
        ObjectRadiusMultiplier = 1.5f;
        
        yield return new WaitForSecondsRealtime(15f);

        transform.localScale /= 1.5f;
        ObjectRadiusMultiplier = 1.0f;
    }

    private IEnumerator OnShrinkPlayerModifier()
    {
        transform.localScale *= 0.6f;
        ObjectRadiusMultiplier = 0.6f;
        
        yield return new WaitForSecondsRealtime(15f);
        
        transform.localScale /= 0.6f;
        ObjectRadiusMultiplier = 1.0f;
    }

    private IEnumerator TriggerInvincibility()
    {
        m_HasFreeHitActive = false;
        m_HasInvincibility = true;

        yield return new WaitForSecondsRealtime(1f);

        m_HasInvincibility = false;
    }

    private IEnumerator OnModiferPickup()
    {
        Vector3 start = TranslateToVector3();
        Vector3 direction = Vector3.zero - start;
        direction.Normalize();
        direction *= 3;
        Vector3 end = start + direction;
        
        m_ModifierText.transform.position = start;

        Color startColor = m_ModifierText.color;
        Color endColor = m_ModifierText.color;
        endColor.a = 0;

        for (float lerp = 0f; lerp < 1f; lerp += Time.deltaTime / 2f)
        {
            m_ModifierText.color = Color.Lerp(startColor, endColor, lerp);
            m_ModifierText.transform.position = Vector3.Lerp(start, end, lerp);
            yield return new WaitForEndOfFrame();
        }

        m_ModifierText.color = startColor;
        m_ModifierText.text = "";

        yield return null;
    }

    protected override void OnOrbitalCollision(OrbitalBehaviour other)
    {
        if (!IsAttachedToRings)
            return;

        if (other.CompareTag("Enemy"))
        {
            if (m_HasInvincibility)
            {
                return;
            }

            if (m_HasFreeHitActive)
            {
                StartCoroutine(TriggerInvincibility());
                return;
            }
            
            StartCoroutine(BehaviourManager.RestartSimulation());
            
            m_SuicidePoint = transform.position;
            m_KillingItself = true;
            m_DeathLerp = 0f;
        }
        
        else if (other.CompareTag("PlayerMod"))
        {
            PlayerModifier mod = (PlayerModifier)other;
            m_ModifierText.text = PlayerModifier.ModifierToString(mod.Modifier);

            StartCoroutine(OnModiferPickup());
            
            switch (mod.Modifier)
            {
                case PlayerModifier.Modifiers.GainPoints:
                    s_PlayerScore += 100;
                    break;
                
                case PlayerModifier.Modifiers.FreeHit:
                    m_HasFreeHitActive = true;
                    break;
                
                case PlayerModifier.Modifiers.GrowPlayer:
                    StartCoroutine(OnGrowPlayerModifier());
                    break;
                
                case PlayerModifier.Modifiers.ShrinkPlayer:
                    StartCoroutine(OnShrinkPlayerModifier());
                    break;
                
                case PlayerModifier.Modifiers.SpeedUp:
                    StartCoroutine(BehaviourManager.StartPlayerSpeedupModifier());
                    break;
                
                case PlayerModifier.Modifiers.ClearAllEnemies:
                    EnemyController.KillAllEnemies();
                    break;
                
                default:
                    Debug.Log($"Collision with unknown modifier occured [{mod.Modifier}]");
                    break;
            }
        }

        else
        {
            Debug.Log("Unknown collision occured");
        }
    }

    protected override void OnSimulationRestart()
    {
        m_KillingItself = false;
        m_Renderer.enabled = true;

        m_HasFreeHitActive = false;
        
        m_Renderer.material.color = Color.green;
        
        s_HighScore = Math.Max(s_HighScore, s_PlayerScore);
        PlayerPrefs.SetInt("HighScore", s_HighScore);
        s_PlayerScore = 0;
    }

    protected override void OnReachCentre()
    {
        StartCoroutine(BehaviourManager.RestartSimulation());
    }

    public static void AttachPlayer()
    {
        Instance.IsAttachedToRings = true;
    }
}
