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

public class Weather : MonoBehaviourSingleton<Weather>
{
    public bool m_active = true;
    public bool m_readData = false;
    public int m_currentMood = 0;

    public float m_fogDensityBoost = 0.2f;
    [System.NonSerialized]
    public float m_fogExtraFactor = 0;

    [System.NonSerialized]
    public WeatherData m_mood;
    WeatherData[] m_moods;

    const float TransitionSpeed = 0.4f;

    private Light m_directionalLight;
    private ParticleSystem m_rainFX;
    private Material m_rainMaterial;

    private float m_rainIntensityTarget;
    private float m_rainIntensity;
    private float m_rainIntensitySpeed = 1;
    private int m_rainSound;

    public void OnInit()
    {
        m_directionalLight = SceneAccess.Find("Sun").GetComponent<Light>();

        GameObject camera = Camera.main.gameObject;

        // rainFX
        Transform rainFXObject = camera.transform.Find("RainFX");
        m_rainFX = rainFXObject.GetComponent<ParticleSystem>();
        m_rainMaterial = rainFXObject.GetComponent<ParticleSystemRenderer>().material;

        m_moods = GetComponentsInChildren<WeatherData>();

        m_currentMood = 0;
        m_mood = GetComponent<WeatherData>();
        m_mood.CopyFrom(m_moods[m_currentMood]);
        WriteWeatherData(m_mood);

        m_rainIntensity = 0;
        m_rainIntensityTarget = 0;
        m_rainSound = -1;

        InitChangeLogic(true);
    }

    /*
    public void OnStop()
    {
        AudioManager.instance.StopSound("Rain");

//@        m_globalFog = null;
        m_rainFX = null;
        m_rainMaterial = null;

        m_moods = null;
    }
    */

    public void SetMood(int mood)
    {
        m_currentMood = mood;
    }

    public Light GetDirectionalLight()
    {
        return m_directionalLight;
    }

    public void ReadWeatherData(ref WeatherData data)
    {
        data.m_lightColor = m_directionalLight.color;
        data.m_lightIntensity = m_directionalLight.intensity;

        data.m_ambientSkyColor = RenderSettings.ambientSkyColor;
        data.m_ambientEquatorColor = RenderSettings.ambientEquatorColor;
        data.m_ambientGroundColor = RenderSettings.ambientGroundColor;

        data.m_skyFogFactor = RenderSettings.skybox.GetFloat("_FogFactor");
        data.m_skyHorizontColor = RenderSettings.skybox.GetColor("_Horizon");

        data.m_fogDenisty = RenderSettings.fogDensity;
        data.m_fogColor = RenderSettings.fogColor;

        // need toread from materials too?
    }

    public void WriteWeatherData(WeatherData data)
    {
        m_directionalLight.color = data.m_lightColor;
        m_directionalLight.intensity = data.m_lightIntensity;

        RenderSettings.ambientSkyColor = data.m_ambientSkyColor;
        RenderSettings.ambientEquatorColor = data.m_ambientEquatorColor;
        RenderSettings.ambientGroundColor = data.m_ambientGroundColor;

        RenderSettings.skybox.SetFloat("_FogFactor", Mathf.Max(data.m_skyFogFactor, 1));
        RenderSettings.skybox.SetColor("_Horizon", data.m_skyHorizontColor);

        float fogDensityScale = 1.0f + m_fogDensityBoost * m_fogExtraFactor;

        RenderSettings.fogDensity = data.m_fogDenisty * fogDensityScale;
        RenderSettings.fogColor = data.m_fogColor;

        

        //m_rainMaterial.SetFloat("_DirectionalLightMultiplier", data.m_rainLight * data.m_rainIntensity); //@HM WHY not here?
        m_rainIntensityTarget = data.m_rainIntensity;
    }

    private void UpdateRain()
    {
        float rainSpeed = m_rainIntensitySpeed; // 1.0f;
        if (m_rainIntensity == m_rainIntensityTarget)
        {
            return;
        }
        else if (m_rainIntensity < m_rainIntensityTarget)
        {
            m_rainIntensity += Time.deltaTime * rainSpeed;
            if (m_rainIntensity > m_rainIntensityTarget)
                m_rainIntensity = m_rainIntensityTarget;
        }
        else if (m_rainIntensity > m_rainIntensityTarget)
        {
            m_rainIntensity -= Time.deltaTime * rainSpeed;
            if (m_rainIntensity < m_rainIntensityTarget)
                m_rainIntensity = m_rainIntensityTarget;
        }

        if (m_rainIntensity > 0)
        {
            if (!m_rainFX.isPlaying)
                m_rainFX.Play();

            if (m_rainSound == -1)
                m_rainSound = AudioManager.instance.PlaySound("Rain", 0, 0, true);
            if (m_rainSound != -1)
                AudioManager.instance.SetVoiceVolume(m_rainSound, m_rainIntensity);

            //@TODO: use the real effect spawn rate, move this back to write data
            m_rainMaterial.SetFloat("_DirectionalLightMultiplier", m_mood.m_rainLight * m_rainIntensity); // @TODO: should use the lerpData?
        }
        else
        {
            if (m_rainFX.isPlaying)
                m_rainFX.Stop();

            if (m_rainSound != -1)
            {
                AudioManager.instance.StopVoice(m_rainSound);
                m_rainSound = -1;
            }
        }
    }

    /*
    private void StartRain(bool fast, bool applyWeatherData)
    {
        if(applyWeatherData)
            WriteWeatherData(m_mood);

        m_rainIntensityTarget = 1;
        m_rainIntensitySpeed = fast ? 2.0f : 0.5f;
    }

    private void StopRain()
    {
        m_rainIntensitySpeed = 0.25f;
        m_rainIntensityTarget = 0;
    }
    */
    public void OnUpdate()
    {
        if (m_active)
        {
            UpdateChangeLogic();

            m_mood.Lerp(m_mood, m_moods[m_currentMood], Time.deltaTime * TransitionSpeed);
            WriteWeatherData(m_mood);
        }
        else
        {
            if (m_readData)
            {
                ReadWeatherData(ref m_mood);
                m_moods[m_currentMood].CopyFrom(m_mood);
                m_readData = false;
            }
        }

        if(m_rainFX)
            UpdateRain();
    }

    // --------------------------------------------------------
    float m_waitMin = 30;
    float m_waitMax = 120;
    float m_changeMin = 10;
    float m_changeMax = 60;
    float m_changeTime;
    float m_changeDuration;
    bool m_theend = false;
    void InitChangeLogic(bool force = false)
    {
        if(Player.instance.m_maxTraveledDistance > Road.instance.m_distance + 10)
        {
            m_theend = true;
            SetMood(2); // white fog
            m_changeDuration = m_waitMax;
            return;
        }

        if (m_currentMood != 0)
        {
            SetMood(0);
            m_changeDuration = GFRandom.RangeOpen(m_waitMin, m_waitMax);
        }
        else
        {
            SetMood(GFRandom.RangeOpen(1, m_moods.Length));
            m_changeDuration = GFRandom.RangeOpen(m_changeMin, m_changeMax);
        }
        m_changeTime = 0;
    }

    void UpdateChangeLogic()
    {
        if (!m_theend)
        {
            m_changeTime += Time.deltaTime;
            if (m_changeTime > m_changeDuration)
                InitChangeLogic();
        }
    }
}
