<?php

class Heizung_x_Stufig extends IPSModule
{
    private array $leistungArray = [];

    public function Create()
    {
        parent::Create();

        $this->RegisterPropertyString("LeistungsStufen", json_encode([]));
        $this->RegisterPropertyInteger("ZeitKonstante", 120);
        $this->RegisterPropertyInteger("Heizungsfuehler", 0);
        $this->RegisterPropertyBoolean("Heizungstemperatur_glätten", false);
        $this->RegisterPropertyInteger("Interval", 5);
        $this->RegisterPropertyFloat("Hysterese", 0.1);

        $this->RegisterVariableInteger("Mindesttemperatur", "Mindesttemperatur", "", 45);
        $this->RegisterVariableInteger("Maximaltemperatur", "Maximaltemperatur", "", 60);
        $this->RegisterVariableFloat("Heizungstemperatur", "Heizungstemperatur", "", 0);

        $this->RegisterVariableBoolean("Disable", "Heizung Ein/Aus", "~Switch", 0);
        $this->EnableAction("Disable");

        $this->RegisterVariableInteger("Sperre_Prio", "Sperre_Prio");
        $this->RegisterVariableInteger("PV_Prio", "PV_Prio");
        $this->RegisterVariableBoolean("Idle", "Idle", "", 0);
        $this->RegisterVariableInteger("Aktuelle_Leistung", "Aktuelle_Leistung", "", 0);
        $this->RegisterVariableFloat("Bezogene_Energie", "Bezogene_Energie", "", 0);
        $this->RegisterVariableString("PowerSteps", "PowerSteps");
        $this->RegisterVariableInteger("Power", "Power", "", 0);
        $this->RegisterVariableBoolean("Is_Peak_Shaving", "Is_Peak_Shaving", "", true);
        $this->RegisterVariableInteger("Leistung_Delta", "Leistung_Delta", "", 0);

        $this->RegisterPropertyInteger("IdleCounterMax", 2);
        $this->RegisterVariableInteger("IdleCounter", "IdleCounter", "", 0);
        $this->SetValue("IdleCounter", 0);

        $this->SetValue("Idle", true);

        $this->RegisterTimer(
            "Timer_Do_UserCalc_Heizung",
            $this->ReadPropertyInteger("Interval") * 1000,
            'IPS_RequestAction(' . $this->InstanceID . ', "Do_UserCalc", "");'
        );
    }

    public function ApplyChanges()
    {
        parent::ApplyChanges();

        $this->SetTimerInterval(
            "Timer_Do_UserCalc_Heizung",
            $this->ReadPropertyInteger("Interval") * 1000
        );
    }

    public function RequestAction($Ident, $Value)
    {
        switch ($Ident) {
            case "Disable":
                $this->SetValue("Disable", (bool)$Value);

                if ((bool)$Value) {
                    $this->SetValue("PowerSteps", json_encode([0]));
                    $this->SetAktuelle_Leistung(0);
                }
                break;

            case "SetAktuelle_Leistung":
                $this->SetValue("Power", (int)$Value);
                break;

            case "GetCurrentData":
                $this->SetValue("Is_Peak_Shaving", (bool)$Value);
                break;

            case "Do_UserCalc":
                $this->SetAktuelle_Leistung($this->GetValue("Power"));
                $this->GetCurrentData($this->GetValue("Is_Peak_Shaving"));
                break;

            default:
                throw new Exception("Invalid Ident");
        }
    }

    private function LadeUndSortiereLeistungen()
    {
        $this->leistungArray = [0];

        $json = $this->ReadPropertyString("LeistungsStufen");
        $leistungsStufen = json_decode($json, true);

        if (is_array($leistungsStufen)) {
            foreach ($leistungsStufen as $stufe) {
                $this->leistungArray[] = (int)($stufe['Leistung'] ?? 0);
            }
        }

        sort($this->leistungArray);
    }

    public function SetAktuelle_Leistung(int $power)
    {
        $this->LadeUndSortiereLeistungen();

        foreach ($this->leistungArray as $leistung) {
            $kontaktID = $this->GetKontaktIDZuLeistung($leistung);

            if ($kontaktID > 0 && IPS_VariableExists($kontaktID)) {
                RequestAction($kontaktID, ($leistung === $power));
            } elseif ($kontaktID > 0) {
                IPS_LogMessage("ERROR", "KontaktID $kontaktID existiert nicht oder ist ungültig!");
            }
        }

        $lastPower = GetValue($this->GetIDForIdent("Aktuelle_Leistung"));

        if ($power != $lastPower) {
            $this->SetValue("Idle", false);
            $this->SetValue("IdleCounter", $this->ReadPropertyInteger("IdleCounterMax"));
        }

        $this->SetValue("Aktuelle_Leistung", $power);

        $this->SetValue(
            "Bezogene_Energie",
            $this->GetValue("Bezogene_Energie") +
            ($this->GetValue("Aktuelle_Leistung") * ($this->ReadPropertyInteger("Interval") / 3600))
        );

        $this->ProcessIdleCounter();
    }

    private function GetKontaktIDZuLeistung(int $leistung): int
    {
        $json = $this->ReadPropertyString("LeistungsStufen");
        $leistungsStufen = json_decode($json, true);

        if (is_array($leistungsStufen)) {
            foreach ($leistungsStufen as $stufe) {
                if ((int)($stufe['Leistung'] ?? 0) === $leistung) {
                    return (int)($stufe['Schaltkontakt_Stufe'] ?? 0);
                }
            }
        }

        return 0;
    }

    public function GetCurrentData(bool $Peak)
    {
        $this->LadeUndSortiereLeistungen();


        /*
        if ($this->GetValue("Disable") == false) {
            $this->SetValue("PowerSteps", json_encode([0]));
            $this->SetAktuelle_Leistung(0);
            return;
        }*/
        $heizungstemperaturGlaetten = $this->ReadPropertyBoolean("Heizungstemperatur_glätten");
        $heizungsFuehlerPT1ID = $this->ReadPropertyInteger("Heizungsfuehler");

        if ($heizungsFuehlerPT1ID > 0 && IPS_VariableExists($heizungsFuehlerPT1ID)) {
            $heizungPT1 = GetValue($heizungsFuehlerPT1ID);
        } else {
            $heizungPT1 = 0.0;
        }

        if ($heizungstemperaturGlaetten) {
            $heizungTempAlt = $this->GetValue("Heizungstemperatur");

            $timeConstant = $this->ReadPropertyInteger("ZeitKonstante");
            $deltaT = $this->ReadPropertyInteger("Interval");

            $alpha = $deltaT / ($timeConstant + $deltaT);
            $newHeizungTemp = $heizungTempAlt + $alpha * ($heizungPT1 - $heizungTempAlt);

            $this->SetValue("Heizungstemperatur", $newHeizungTemp);
        } else {
            $this->SetValue("Heizungstemperatur", $heizungPT1);
        }

        if ($this->GetValue("Disable") == false){
            $dummy_array[] = 0;
            return $this->SetValue("PowerSteps", json_encode($dummy_array));
        }





        $heizungTemp = $this->GetValue("Heizungstemperatur");
        $minTemp = $this->GetValue("Mindesttemperatur");
        $maxTemp = $this->GetValue("Maximaltemperatur");
        $hysterese = $this->ReadPropertyFloat("Hysterese");

        $vollLeistung = max($this->leistungArray);

        if ($Peak) {
            if ($heizungTemp < $minTemp) {
                $this->SetValue("PowerSteps", json_encode($this->leistungArray));
            } elseif (
                $heizungTemp < $minTemp + $hysterese &&
                $this->IstEineStufeAktiv()
            ) {
                $this->SetValue("PowerSteps", json_encode($this->leistungArray));
            } else {
                $this->SetValue("PowerSteps", json_encode([0]));
            }
        } else {
            if ($heizungTemp < $minTemp) {
                $this->SetValue("PowerSteps", json_encode([$vollLeistung]));
            } elseif (
                $heizungTemp < $minTemp + $hysterese &&
                $this->IstEineStufeAktiv()
            ) {
                $this->SetValue("PowerSteps", json_encode([$vollLeistung]));
            } elseif ($heizungTemp < $maxTemp - $hysterese) {
                $this->SetValue("PowerSteps", json_encode($this->leistungArray));
            } elseif (
                $heizungTemp < $maxTemp &&
                $this->IstEineStufeAktiv()
            ) {
                $this->SetValue("PowerSteps", json_encode($this->leistungArray));
            } else {
                $this->SetValue("PowerSteps", json_encode([0]));
            }
        }
    }

    private function IstEineStufeAktiv(): bool
    {
        $json = $this->ReadPropertyString("LeistungsStufen");
        $leistungsStufen = json_decode($json, true);

        if (is_array($leistungsStufen)) {
            foreach ($leistungsStufen as $stufe) {
                $kontaktID = (int)($stufe['Schaltkontakt_Stufe'] ?? 0);

                if ($kontaktID > 0 && IPS_VariableExists($kontaktID)) {
                    if (GetValue($kontaktID) === true) {
                        return true;
                    }
                }
            }
        }

        return false;
    }

    private function ProcessIdleCounter()
    {
        $idleCounter = $this->GetValue("IdleCounter");

        if ($idleCounter > 0) {
            $this->SetValue("Idle", false);
            $this->SetValue("IdleCounter", $idleCounter - 1);
        } else {
            $this->SetValue("Idle", true);
        }
    }
}

?>