using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;


public class GameBoss : MonoBehaviour
{
    public GameObject dingleBopStatus;
    public GameObject batteryA;
    public GameObject batteryB;
    public GameObject batteryToggleA;
    public GameObject batteryToggleB;

    public GameObject warningLights;

    public GameObject dingleBop1;
    public GameObject dingleBop2;
    public GameObject dingleBop3;

    // LEDS
    public GameObject ledVent;
    public GameObject ledBattery;

    // Buttons
    public GameObject ventButton;
    public GameObject PATGButton;

    public GameObject defCamera;

    public GameObject Coregauge;
    
    // Time
    public GameObject TimeEnduredMin;
    public GameObject TimeEnduredSec;


    // motion compensator

    public GameObject ledIn1;
    public GameObject ledIn2;
    public GameObject ledIn3;
    public GameObject ledIn4;

    public GameObject toggle1;
    public GameObject toggle2;
    public GameObject toggle3;
    public GameObject toggle4;

    public GameObject ledOut1;
    public GameObject ledOut2;
    public GameObject ledOut3;
    public GameObject ledOut4;

    public GameObject compensatorActive;
    public GameObject compensatorInactive;

    public GameObject warningStatus;

    public Sprite diff1;
    public Sprite diff2;
    public Sprite diff3;
    public Sprite diff4;
    public Sprite diff5;

    public AudioSource randomChange;
    public AudioSource diffIncrease;

    private int maxDifficultyTicks = 800;
    private int ticksTilRandomEvent = 240;


    [Range(0,100)]
    public float Chaos = 0;

    private int ticks = 0;
    private int diffTicks = 0;

    // TMP
    private LNodeInvert batStatus;
    LNodeSummation stabilityOutput;
    // Start is called before the first frame update

    LNodeSummation dinglebopSummation;
    private float currentStabilization = 0.5f;
    private float t;


    LNodeRange dinglebopRange;
    void Start()
    {
        setupChain();

        updateLEDs();

    }

    private void changeDinglebopRange()
    {
        float rnd = Random.value;
        dinglebopRange.setVal(new LNodeConstant(rnd));
        dingleBopStatus.GetComponentInChildren<LevelGuageWrange>().setRange(rnd, 0.3f);
    }

    private void setupChain()
    {
        stabilityOutput = new LNodeSummation();

        dinglebopSummation = new LNodeSummation();

        // Sum the dinglebops
        dinglebopSummation.AddNode(new LNodeDingleBopExtract(dingleBop1.GetComponentInChildren<DingleBopScript>()), 3);
        dinglebopSummation.AddNode(new LNodeDingleBopExtract(dingleBop2.GetComponentInChildren<DingleBopScript>()), 1);
        dinglebopSummation.AddNode(new LNodeDingleBopExtract(dingleBop3.GetComponentInChildren<DingleBopScript>()), 2);

        
        dinglebopRange = new LNodeRange(new LNodeConstant(0.5f), new LNodeConstant(0.1f), dinglebopSummation);
        dingleBopStatus.GetComponentInChildren<LevelGuageWrange>().setRange(0.5f, 0.3f);


        // Get the status of the vent LED
        LNodeInvert ventStatus = new LNodeInvert(new LLEDStatus(ledVent.GetComponentInChildren<ButtonScript>()));
        LNodeGate gated = new LNodeGate(ventStatus, dinglebopRange, new LNodeConstant(0.2f));



        stabilityOutput.AddNode(gated);


        // Get the status of the battery node
        batStatus = new LNodeInvert(new LLEDStatus(ledBattery.GetComponentInChildren<ButtonScript>()));
        LNodeGate batGated = new LNodeGate(batStatus, new LNodeConstant(0.5f), new LNodeConstant(0.1f));
        stabilityOutput.AddNode(batGated);


        // Get the status of the compensator node
        batStatus = new LNodeInvert(new LLEDStatus(compensatorInactive.GetComponentInChildren<ButtonScript>()));
        LNodeGate batComp = new LNodeGate(batStatus, new LNodeConstant(0.5f), new LNodeConstant(0.1f));
        stabilityOutput.AddNode(batComp);


        //stabilityOutput.AddNode(dinglebopSummation);
    }
    // Update is called once per frame
    void Update()
    {
        
    }

    private void turnPATGon()
    {
   //     Debug.Log("Turning PATG on");
        PATGButton.GetComponentInChildren<GenericTestButtonScript>().toggleOn();
    }

    private void turnVentLedOn()
    {
        //   Debug.Log("Turning Vent LED on");
        ledVent.GetComponentInChildren<ButtonScript>().setStatus(true);
    }

    private void  updateTimeCounter(float time)
    {
        System.TimeSpan t = System.TimeSpan.FromSeconds(time);
        
        TimeEnduredMin.GetComponent<Text>().text = string.Format("{0:D2}", t.Minutes);
        TimeEnduredSec.GetComponent<Text>().text = string.Format("{0:D2}", t.Seconds);
    }

    public void randomizeLEDs()
    {
        ledIn1.GetComponentInChildren<ButtonScript>().setStatus(Random.value > 0.5f);
        ledIn2.GetComponentInChildren<ButtonScript>().setStatus(Random.value > 0.5f);
        ledIn3.GetComponentInChildren<ButtonScript>().setStatus(Random.value > 0.5f);
        ledIn4.GetComponentInChildren<ButtonScript>().setStatus(Random.value > 0.5f);

        checkLEDAndUpdate();
    }

    public void updateLEDs()
    {       
        ledOut1.GetComponentInChildren<ButtonScript>().setStatus(toggle1.GetComponentInChildren<GenericTestButtonScript>().IsOn);
        ledOut2.GetComponentInChildren<ButtonScript>().setStatus(toggle2.GetComponentInChildren<GenericTestButtonScript>().IsOn);
        ledOut3.GetComponentInChildren<ButtonScript>().setStatus(toggle3.GetComponentInChildren<GenericTestButtonScript>().IsOn);
        ledOut4.GetComponentInChildren<ButtonScript>().setStatus(toggle4.GetComponentInChildren<GenericTestButtonScript>().IsOn);

        checkLEDAndUpdate();
    }

    private bool checkLEDs()
    {
        if (ledOut1.GetComponentInChildren<ButtonScript>().IsOn != ledIn1.GetComponentInChildren<ButtonScript>().IsOn)
            return false;


        if (ledOut2.GetComponentInChildren<ButtonScript>().IsOn != ledIn2.GetComponentInChildren<ButtonScript>().IsOn)
            return false;
        
        if (ledOut3.GetComponentInChildren<ButtonScript>().IsOn != ledIn3.GetComponentInChildren<ButtonScript>().IsOn)
            return false;

        if (ledOut4.GetComponentInChildren<ButtonScript>().IsOn != ledIn4.GetComponentInChildren<ButtonScript>().IsOn)
            return false;
        
        return true;
    }

    private void checkLEDAndUpdate()
    {
        if (checkLEDs())
        {
            compensatorActive.GetComponentInChildren<ButtonScript>().setStatus(true);
            compensatorInactive.GetComponentInChildren<ButtonScript>().setStatus(false);
        } else
        {
            compensatorActive.GetComponentInChildren<ButtonScript>().setStatus(false);
            compensatorInactive.GetComponentInChildren<ButtonScript>().setStatus(true);
        }
    }
    private void increaseDifficulty()
    {
        ticksTilRandomEvent = Mathf.RoundToInt(Mathf.Clamp(ticksTilRandomEvent - 40, 50, 20000));
        Debug.Log("Difficulty is now " + ticksTilRandomEvent);

        diffIncrease.Play();

        if (ticksTilRandomEvent == 200)
            warningStatus.GetComponent<SpriteRenderer>().sprite = diff2;
        if (ticksTilRandomEvent == 140)
            warningStatus.GetComponent<SpriteRenderer>().sprite = diff3;
        if (ticksTilRandomEvent == 80)
            warningStatus.GetComponent<SpriteRenderer>().sprite = diff4;
        if (ticksTilRandomEvent == 40)
            warningStatus.GetComponent<SpriteRenderer>().sprite = diff5;

    }

    private void FixedUpdate()
    {
        // F. U. Uniteeeee
        if (stabilityOutput == null)
            setupChain();

        // Update time
        t += Time.deltaTime;
        updateTimeCounter(t);


        // Set dinglebop levels               
        dingleBopStatus.GetComponent<LevelGuageWrange>().setValue(dinglebopSummation.getOutput());


        // The current process instability
        float currentStab = stabilityOutput.getOutput() - 0.5f;

        //Debug.Log("Cur Stab: " + currentStab);

        // The rate of change
        float rateOfChange = 0.005f;

        // The current stability after adding this ticks instability*rateOfChange
        currentStabilization = Mathf.Clamp01(currentStabilization + (currentStab * rateOfChange));

        // Flashing
        warningLights.GetComponent<WarningLightScriipt>().IsFlickering = Mathf.Abs(currentStabilization) < 0.3f;

        // Camera shake
        float deviance = (Mathf.Pow(Mathf.Abs((1 - currentStabilization) - 0.5f), 3) * 4) * 0.5f;
        defCamera.transform.position = new Vector3(Random.value * deviance, Random.value * deviance, 1);

        // Set core stability
        Coregauge.GetComponent<CoreGauge>().setValue(currentStabilization * 100f);



        if (currentStabilization == 0 || currentStabilization == 1) {
            PlayerPrefs.SetFloat("score", t);
            SceneManager.LoadScene("GameOver");
        }



        if (batteryA.GetComponent<BatteryIndicatorScript>().hasCharge() || batteryB.GetComponent<BatteryIndicatorScript>().hasCharge())
            ledBattery.GetComponentInChildren<ButtonScript>().setStatus(false);
        else
            ledBattery.GetComponentInChildren<ButtonScript>().setStatus(true);


        if (ventButton.GetComponentInChildren<GenericTestButtonScript>().stateChanged())
        {
            if (ledVent.GetComponentInChildren<ButtonScript>().IsOn)
            {
                ledVent.GetComponentInChildren<ButtonScript>().setStatus(false);
            }
        }


        if (batteryToggleA.GetComponentInChildren<GenericTestButtonScript>().stateChanged())
        {
            if (batteryToggleA.GetComponentInChildren<GenericTestButtonScript>().IsOn)
                batteryA.GetComponent<BatteryIndicatorScript>().charge();
            else
                batteryA.GetComponent<BatteryIndicatorScript>().discharge();
        }

        if (batteryToggleB.GetComponentInChildren<GenericTestButtonScript>().stateChanged())
        {
            if (batteryToggleB.GetComponentInChildren<GenericTestButtonScript>().IsOn)
                batteryB.GetComponent<BatteryIndicatorScript>().charge();
            else
                batteryB.GetComponent<BatteryIndicatorScript>().discharge();
        }


        if (toggle1.GetComponentInChildren<GenericTestButtonScript>().stateChanged() || toggle2.GetComponentInChildren<GenericTestButtonScript>().stateChanged() || toggle3.GetComponentInChildren<GenericTestButtonScript>().stateChanged() || toggle4.GetComponentInChildren<GenericTestButtonScript>().stateChanged()) { 
            updateLEDs();
        }

        ticks++;
        if (ticks > ticksTilRandomEvent) {
            Debug.Log("Random event");

            randomChange.Play();
            
            switch (Mathf.RoundToInt(Random.value * 4)) {
                case 0: 
                    turnPATGon();
                    break;
                case 1: 
                    turnVentLedOn();
                    break;
                case 2:
                    changeDinglebopRange();
                    break;
                case 3:
                    randomizeLEDs();
                    break;
            }
                   
            ticks = 0;
        }
        
        diffTicks++;

        if (diffTicks > maxDifficultyTicks)
        {
            increaseDifficulty();
            diffTicks = 0;
        }
    }
}
