<?php
declare(strict_types=1);

include_once __DIR__ . '/libs/vendor/autoload.php'; // TCPDF via Composer

/**
 * Eigene TCPDF-Klasse mit Logo im Header und Text in der Fusszeile
 */

class InvoicePDF extends TCPDF
{
    public $logoFile = null;
    public $footerText = '';
    public $printFooterText = true; // Neu: Steuert ob die Fusszeile gedruckt wird

    public function Header()
    {
        if ($this->logoFile !== null && file_exists($this->logoFile)) {
            $this->Image($this->logoFile, 15, 10, 40);
            $this->SetY(28);
        } else {
            $this->SetY(15);
        }
    }

    public function Footer()
    {
        if (!$this->printFooterText) {
            return; // Auf QR-Seite keine Rechnungs-Fusszeile drucken!
        }
        $this->SetY(-15);
        $this->SetFont('dejavusans', '', 8);
        $this->Cell(0, 10, $this->footerText, 0, 0, 'C');
    }
}

class Abrechnung extends IPSModule
{
    public function Create()
    {
        parent::Create();

        $this->RegisterPropertyString('Users', '[]');
        $this->RegisterPropertyString('PowerMeters', '[]');
        $this->RegisterPropertyString('WaterMeters', '[]');
        $this->RegisterPropertyString('Tariffs', '[]');
        $this->RegisterPropertyInteger('LogoMediaID', 0);
        $this->RegisterPropertyString('PropertyText', 'Liegenschaft');
        $this->RegisterPropertyString('FooterText', 'Belevo AG • 6122 Menznau • www.belevo.ch');
        
        // NEU: MWST Variablen registrieren (Standard 8.1%)
        $this->RegisterPropertyBoolean('EnableVAT', false);
        $this->RegisterPropertyFloat('VATPercentage', 8.1);

        // Neue Felder für den QR-Schein
        $this->RegisterPropertyString('CreditorName', 'Belevo AG');
        $this->RegisterPropertyString('CreditorAddress', 'Musterstrasse 1');
        $this->RegisterPropertyString('CreditorCity', '6122 Menznau');
        $this->RegisterPropertyString('BankIBAN', '');

        $this->RegisterVariableInteger('FromDate', 'Startdatum', '~UnixTimestamp', 1);
        $this->RegisterVariableInteger('ToDate', 'Enddatum', '~UnixTimestamp', 2);
        $this->RegisterVariableString('LastResult', 'Letzte Abrechnung', '', 3);
        $this->EnableAction('FromDate');
        $this->EnableAction('ToDate');

        $this->RegisterScript(
            'StartBilling',
            'Abrechnung starten',
            "<?php IPS_RequestAction(" . $this->InstanceID . ", 'StartBilling', ''); ?>"
        );
        $this->RegisterMediaDocument('InvoicePDF', 'Letzte Rechnung', 'pdf');
    }

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

    private function RegisterMediaDocument($Ident, $Name, $Extension, $Position = 0)
    {
        $mid = @IPS_GetObjectIDByIdent($Ident, $this->InstanceID);
        if ($mid === false) {
            $mid = IPS_CreateMedia(5);
            IPS_SetParent($mid, $this->InstanceID);
            IPS_SetIdent($mid, $Ident);
            IPS_SetName($mid, $Name);
            IPS_SetPosition($mid, $Position);
            IPS_SetMediaFile($mid, 'media/' . $mid . '.' . $Extension, false);
        }
    }

    public function RequestAction($Ident, $Value)
    {
        switch ($Ident) {
            case 'FromDate':
            case 'ToDate':
                SetValue($this->GetIDForIdent($Ident), $Value);
                break;

            case 'StartBilling':
                try {
                    $pdfContent = $this->GenerateInvoices();
                    if (!$pdfContent) {
                        echo "❌ Fehler bei der PDF-Erstellung";
                        return;
                    }

                    $mediaID = $this->GetIDForIdent('InvoicePDF');
                    IPS_SetMediaContent($mediaID, base64_encode($pdfContent));
                    SetValue($this->GetIDForIdent('LastResult'), 'Abrechnung vom ' . date('d.m.Y H:i'));
                    echo "✅ PDF erfolgreich erstellt.";
                } catch (Throwable $e) {
                    echo "❌ Ausnahmefehler: " . $e->getMessage();
                }
                break;
        }
    }

    // ====================== PDF-Erstellung ======================

public function GenerateInvoices()
    {
        $from = GetValue($this->GetIDForIdent('FromDate'));
        $to   = GetValue($this->GetIDForIdent('ToDate'));

        $users   = json_decode($this->ReadPropertyString('Users'), true);
        $power   = json_decode($this->ReadPropertyString('PowerMeters'), true);
        $water   = json_decode($this->ReadPropertyString('WaterMeters'), true);
        $tariffs = json_decode($this->ReadPropertyString('Tariffs'), true);

        if (!class_exists('TCPDF')) {
            return false;
        }

        // Stromkosten einmal für alle User berechnen (15-Minuten-Logik)
        $this->CalculateAllPowerCosts($power, $tariffs, $from, $to);

        // Logo & Fusszeile vorbereiten
        $logoFile   = $this->GetLogoFile();
        $footerText = $this->ReadPropertyString('FooterText');

        // PDF-Objekt
        $pdf = new InvoicePDF('P', 'mm', 'A4', true, 'UTF-8', false);
        $pdf->logoFile   = $logoFile;
        $pdf->footerText = $footerText;

        $pdf->SetCreator('IPSymcon Abrechnung');
        // Oben mehr Platz für Logo lassen
        $pdf->SetMargins(15, 35, 15);
        $pdf->SetAutoPageBreak(true, 20);
        $pdf->SetFont('dejavusans', '', 8);

        foreach ($users as $user) {
            $pdf->AddPage();
            $pdf->printFooterText = true; // Fusszeile für diese Rechnungsseite EINSCHALTEN
            
            $grandTotal = $this->BuildUserInvoice($pdf, $user, $power, $water, $tariffs, $from, $to);
            
            $this->BuildQRBill($pdf, $user, $grandTotal);
        }

        return $pdf->Output('Abrechnung.pdf', 'S');
    }

    private function BuildUserInvoice($pdf, $user, $power, $water, $tariffs, $from, $to)
    {
        // Kopfbereich
        $html  = "
        <h1 style='text-align:center; margin-bottom:0;'>Elektro- und Nebenkostenabrechnung</h1>
        <h4 style='text-align:center; margin-bottom:0;'>Betrifft Liegenschaft: " . $this->ReadPropertyString("PropertyText") . " </h4>

        <hr>
    
        <table width='100%' style='font-size:10px;'>
            <tr>
                <td width='60%'>
                <strong>Zählpunkte:</strong><br>";

        // Alle Zählerpunkte des Users auflisten
        foreach ($power as $m) {
            if ($m['user_id'] == $user['id']) {
                $html .= htmlspecialchars($m['name']) . "<br>";
            }
        }
        foreach ($water as $m) {
            if ($m['user_id'] == $user['id']) {
                $html .= htmlspecialchars($m['name']) . "<br>";
            }
        }

        $html .= "
                </td>
                <td width='40%'>
                     <strong>Rechnungsadresse:</strong><br>
                    {$user['name']}<br>
                    {$user['address']}<br>
                    {$user['city']}<br>
                </td>
            </tr>
        </table>
        <p style='font-size:8px; margin-top:10px;'>
            <strong>Abrechnungszeitraum:</strong> " . date('d.m.Y', $from) . " – " . date('d.m.Y', $to) . "
        </p>
        <hr><br>
        ";

        // ========================= Elektrizität =========================
        $html .= "<br><h2 style='margin-bottom:3px;margin-top:10px; font-size:10px;'>Elektrizität</h2>";

        $powerResult = $this->GetCalculatedPowerCosts($user['id']);
        $html .= $powerResult['html'];
        $totalPower = $powerResult['sum'];

        // Elektrizitätstarife anzeigen
        $appliedTariffs = $this->CollectTariffsForUser($tariffs, ['Netztarif', 'Solartarif', 'Einspeisetarif']);
        if (!empty($appliedTariffs)) {
            $html .= "<p style='font-size:8px; margin-top:4px;'><strong>Angewendete Elektrizitätstarife:</strong></p>
                      <ul style='font-size:8px;'>";
            foreach ($appliedTariffs as $t) {
                $html .= "<li>"
                    . date('d.m.Y', $t['start']) . " – " . date('d.m.Y', $t['end'])
                    . " — <strong>" . number_format($t['price'], 2) . " Rp/kWh</strong>"
                    . "</li>";
            }
            $html .= "</ul><br><hr><br>";
        }

        // ========================= Nebenkosten =========================
        $html .= "<br><h2 style='margin-bottom:3px; font-size:10px;'>Nebenkosten</h2>";

        $additionalResult = $this->CalculateAdditionalCosts($water, $tariffs, $user['id'], $from, $to);
        $html .= $additionalResult['html'];
        $totalAdditional = $additionalResult['sum'];

        // ========================= Gesamttotal & MWST =========================
        $subTotal = $totalPower + $totalAdditional;
        $enableVAT = $this->ReadPropertyBoolean('EnableVAT');
        
        $html .= "<table width='100%' style='font-size:10px;' cellpadding='2'>";
        
        if ($enableVAT) {
            $vatPercent = $this->ReadPropertyFloat('VATPercentage');
            $vatAmount = $subTotal * ($vatPercent / 100);
            $grandTotal = $subTotal + $vatAmount;
            
            $html .= "
            <tr>
                <td width='75%' align='right'>Zwischentotal (exkl. MWST):</td>
                <td width='25%' align='right'>CHF " . number_format($subTotal, 2, '.', "'") . "</td>
            </tr>
            <tr>
                <td width='75%' align='right'>zuzüglich " . number_format($vatPercent, 1, '.', "'") . " % MWST:</td>
                <td width='25%' align='right'>CHF " . number_format($vatAmount, 2, '.', "'") . "</td>
            </tr>
            <tr>
                <td width='75%' align='right' style='font-size:12px;'><br><strong>Gesamttotal (inkl. MWST):</strong></td>
                <td width='25%' align='right' style='font-size:12px;'><br><strong>CHF " . number_format($grandTotal, 2, '.', "'") . "</strong></td>
            </tr>
            </table>";
        } else {
            $grandTotal = $subTotal;
            $html .= "
            <tr>
                <td width='75%' align='right' style='font-size:12px;'><strong>Gesamttotal:</strong></td>
                <td width='25%' align='right' style='font-size:12px;'><strong>CHF " . number_format($grandTotal, 2, '.', "'") . "</strong></td>
            </tr>
            <tr>
                <td colspan='2' align='right' style='font-size:8px; color:#555;'><br>Nicht mehrwertsteuerpflichtig.</td>
            </tr>
            </table>
            ";
        }

        $pdf->writeHTML($html, true, false, true, false, '');

        // WICHTIG: Total zurückgeben für den Einzahlungsschein
        return $grandTotal;
    }

    // ====================== QR-Einzahlungsschein (Schweiz) ======================

private function BuildQRBill($pdf, $user, $amount)
    {
        $iban = str_replace(' ', '', $this->ReadPropertyString('BankIBAN'));
        
        if (empty($iban) || $amount <= 0) {
            return;
        }

        $pdf->AddPage(); // Schliesst die vorherige Seite (Fusszeile wird dort noch gedruckt)
        $pdf->printFooterText = false; // Fusszeile für diese QR-Seite AUSSCHALTEN
        $pdf->SetAutoPageBreak(false);

        // Wir nutzen Helvetica für den QR-Schein (Standard gemäss Richtlinien)
        $font = 'helvetica';
        $yStart = 192; 

        // Trennlinien zeichnen (Scherensymbol)
        $pdf->SetLineStyle(['dash' => '2,2', 'color' => [0, 0, 0], 'width' => 0.1]);
        $pdf->Line(0, $yStart, 210, $yStart); // Horizontal
        $pdf->Line(62, $yStart, 62, 297);     // Vertikal
        $pdf->SetLineStyle(['dash' => 0, 'color' => [0, 0, 0]]); // Reset

        $creditorName = $this->ReadPropertyString('CreditorName');
        $creditorCity = $this->ReadPropertyString('CreditorCity');
        $bankIBAN_formatted = wordwrap($iban, 4, ' ', true);

        // --- LINKER TEIL: Empfangsschein (0-62mm) ---
        $pdf->SetFont($font, 'B', 11);
        $pdf->SetXY(5, $yStart + 5);
        $pdf->Cell(52, 5, 'Empfangsschein', 0, 1);

        $pdf->SetFont($font, 'B', 6);
        $pdf->SetXY(5, $yStart + 12);
        $pdf->Cell(52, 3, 'Konto / Zahlbar an', 0, 1);
        $pdf->SetFont($font, '', 8);
        $pdf->SetX(5); $pdf->Cell(52, 3, $bankIBAN_formatted, 0, 1);
        $pdf->SetX(5); $pdf->Cell(52, 3, $creditorName, 0, 1);
        $pdf->SetX(5); $pdf->Cell(52, 3, $creditorCity, 0, 1);

        $pdf->SetFont($font, 'B', 6);
        $pdf->SetXY(5, $yStart + 35);
        $pdf->Cell(52, 3, 'Zahlbar durch', 0, 1);
        $pdf->SetFont($font, '', 8);
        $pdf->SetX(5); $pdf->Cell(52, 3, $user['name'] ?? '', 0, 1);
        $pdf->SetX(5); $pdf->Cell(52, 3, $user['address'] ?? '', 0, 1);
        $pdf->SetX(5); $pdf->Cell(52, 3, $user['city'] ?? '', 0, 1);

        // Währung und Betrag unten Links
        $pdf->SetFont($font, 'B', 6);
        $pdf->SetXY(5, $yStart + 65);
        $pdf->Cell(15, 3, 'Währung', 0, 0);
        $pdf->Cell(20, 3, 'Betrag', 0, 1);
        $pdf->SetFont($font, '', 8);
        $pdf->SetX(5);
        $pdf->Cell(15, 4, 'CHF', 0, 0);
        $pdf->Cell(20, 4, number_format($amount, 2, '.', ' '), 0, 1); // Leerzeichen bei Tausender

        // Annahmestelle
        $pdf->SetFont($font, 'B', 6);
        $pdf->SetXY(38, $yStart + 85);
        $pdf->Cell(19, 3, 'Annahmestelle', 0, 1, 'R');


        // --- RECHTER TEIL: Zahlteil ---
        $pdf->SetFont($font, 'B', 11);
        $pdf->SetXY(67, $yStart + 5);
        $pdf->Cell(50, 5, 'Zahlteil', 0, 1);

        // QR Code rendern
        $qrString = $this->GenerateQRString($iban, $amount, $user);
        $style = ['border' => false, 'padding' => 0, 'fgcolor' => [0, 0, 0], 'bgcolor' => false];
        $pdf->write2DBarcode($qrString, 'QRCODE,M', 67, $yStart + 17, 46, 46, $style, 'N');

        // Schweizer Kreuz über den QR Code zeichnen (Spezifikation: 7x7mm inkl. weissem Rand)
        $cX = 67 + 23;           // Zentrum X des QR Codes (Position 67 + Hälfte von 46)
        $cY = $yStart + 17 + 23; // Zentrum Y des QR Codes (Position 17 + Hälfte von 46)

        $pdf->SetFillColor(255, 255, 255);
        $pdf->Rect($cX - 3.5, $cY - 3.5, 7, 7, 'F');
        $pdf->SetFillColor(0, 0, 0);
        $pdf->Rect($cX - 3, $cY - 3, 6, 6, 'F');
        $pdf->SetFillColor(255, 255, 255);
        $pdf->Rect($cX - 0.6, $cY - 2, 1.2, 4, 'F');
        $pdf->Rect($cX - 2, $cY - 0.6, 4, 1.2, 'F');

        // Währung und Betrag unter dem QR Code
        $pdf->SetFont($font, 'B', 8);
        $pdf->SetXY(67, $yStart + 68);
        $pdf->Cell(15, 4, 'Währung', 0, 0);
        $pdf->Cell(20, 4, 'Betrag', 0, 1);
        $pdf->SetFont($font, '', 10);
        $pdf->SetX(67);
        $pdf->Cell(15, 5, 'CHF', 0, 0);
        $pdf->Cell(20, 5, number_format($amount, 2, '.', ' '), 0, 1);

        // --- RECHTE TEXTSPALTE (ab 118mm) ---
        $pdf->SetFont($font, 'B', 8);
        $pdf->SetXY(118, $yStart + 5);
        $pdf->Cell(80, 4, 'Konto / Zahlbar an', 0, 1);
        $pdf->SetFont($font, '', 10);
        $pdf->SetX(118); $pdf->Cell(80, 4, $bankIBAN_formatted, 0, 1);
        $pdf->SetX(118); $pdf->Cell(80, 4, $creditorName, 0, 1);
        $pdf->SetX(118); $pdf->Cell(80, 4, $creditorCity, 0, 1);

        $pdf->SetFont($font, 'B', 8);
        $pdf->SetXY(118, $yStart + 26);
        $pdf->Cell(80, 4, 'Zusätzliche Informationen', 0, 1);
        $pdf->SetFont($font, '', 10);
        $pdf->SetX(118); $pdf->Cell(80, 4, 'Abrechnung Liegenschaft', 0, 1);

        $pdf->SetFont($font, 'B', 8);
        $pdf->SetXY(118, $yStart + 43);
        $pdf->Cell(80, 4, 'Zahlbar durch', 0, 1);
        $pdf->SetFont($font, '', 10);
        $pdf->SetX(118); $pdf->Cell(80, 4, $user['name'] ?? '', 0, 1);
        $pdf->SetX(118); $pdf->Cell(80, 4, $user['address'] ?? '', 0, 1);
        $pdf->SetX(118); $pdf->Cell(80, 4, $user['city'] ?? '', 0, 1);
    }

private function GenerateQRString($iban, $amount, $user)
    {
        // Daten nach SIX Swiss Payment Standard beschneiden (max 70 Zeichen pro Zeile)
        $creditorName = mb_substr($this->ReadPropertyString('CreditorName'), 0, 70);
        $creditorStr  = mb_substr($this->ReadPropertyString('CreditorAddress'), 0, 70);
        $creditorCity = mb_substr($this->ReadPropertyString('CreditorCity'), 0, 70);

        // Fallback falls ein Mieter keinen Namen oder Ort hinterlegt hat (Banken verlangen das zwingend)
        $debtorName   = mb_substr(empty($user['name']) ? 'Unbekannt' : $user['name'], 0, 70);
        $debtorStr    = mb_substr($user['address'] ?? '', 0, 70);
        $debtorCity   = mb_substr(empty($user['city']) ? 'Unbekannt' : $user['city'], 0, 70);

        $amountStr = number_format($amount, 2, '.', '');

        // EPC / Swiss QR Code String Format (Exakte Reihenfolge ist kritisch!)
        $lines = [
            'SPC', '0200', '1', $iban, 'K', 
            $creditorName, $creditorStr, $creditorCity, '', '', 'CH',
            '', '', '', '', '', '', '', // Ultimate Creditor (leer)
            $amountStr, 'CHF', 'K', 
            $debtorName, $debtorStr, $debtorCity, '', '', 'CH',
            'NON', '', // Reference Type (NON = Ohne Referenz)
            'Abrechnung Liegenschaft', // 30. Unstrukturierte Mitteilung
            'EPD' // 31. Trailer (Zwingend exakt 'EPD' am Schluss!)
        ];

        return implode("\r\n", $lines);
    }
    // ====================== Stromkosten (15-Minuten, alle User) ======================

    private function CalculateAllPowerCosts($powerMeters, $tariffs, $from, $to)
    {
        $this->powerCostCache = [];

        // Zähler je User aufbauen
        $metersByUser = [];
        foreach ($powerMeters as $m) {
            if (!isset($m['user_id'])) {
                continue;
            }

            $userId = (int)$m['user_id'];
            $name   = $m['name'] ?? ('Meter_' . $m['user_id']);

            if (!isset($metersByUser[$userId])) {
                $metersByUser[$userId] = [];
            }
            $metersByUser[$userId][$name] = [
                'importVar' => $m['var_consumption'] ?? null,
                'exportVar' => $m['var_feed'] ?? null
            ];

            if (!isset($this->powerCostCache[$userId])) {
                $this->powerCostCache[$userId] = [];
            }
            $this->powerCostCache[$userId][$name] = [
                'name'             => $name,
                'imp'              => 0.0,
                'exp'              => 0.0,
                'solar_bezug'      => 0.0,
                'netz_bezug'       => 0.0,
                'solareinspeisung' => 0.0,
                'solarverkauf'     => 0.0,
                'cost_solar'       => 0.0,
                'cost_grid'        => 0.0,
                'rev_feedin'       => 0.0, 
                'rev_zev'          => 0.0
            ];
        }

        if (empty($metersByUser)) {
            return;
        }

            // 15-Minuten-Schritte
        for ($ts = $from; $ts < $to; $ts += 900) {
            $slotEnd = min($to, $ts + 900);

            // Tarife (gleich für alle User)
            $pGrid  = $this->getTariffPriceAt($tariffs, ['Netztarif'], $ts);
            $pSolar = $this->getTariffPriceAt($tariffs, ['Solartarif'], $ts);
            $pFeed  = $this->getTariffPriceAt($tariffs, ['Einspeisetarif'], $ts);

            // ==========================================================
            // 1) GLOBAL DELTAS EINMAL BERECHNEN
            // ==========================================================
            $globalImpTotal = 0.0;
            $globalExpTotal = 0.0;
            $globalSlot     = [];

            foreach ($powerMeters as $m) {

                $name = $m['name'];
                $impDelta = 0.0;
                $expDelta = 0.0;

                // IMPORT
                if (!empty($m['var_consumption']) && IPS_VariableExists((int)$m['var_consumption'])) {
                    $impDelta = $this->getDeltaFromArchive((int)$m['var_consumption'], $ts, $slotEnd);
                }

                // EXPORT
                if (!empty($m['var_feed']) && IPS_VariableExists((int)$m['var_feed'])) {
                    $expDelta = $this->getDeltaFromArchive((int)$m['var_feed'], $ts, $slotEnd);
                }

                if ($impDelta > 0.0 || $expDelta > 0.0) {
                    $globalSlot[$name] = [
                        'imp' => $impDelta,
                        'exp' => $expDelta,
                        'user_id' => (int)$m['user_id']
                    ];

                    $globalImpTotal += $impDelta;
                    $globalExpTotal += $expDelta;
                }
            }

            // Wenn keine Imp/Exp vorhanden → nächster Slot
            if ($globalImpTotal == 0.0 && $globalExpTotal == 0.0) {
                continue;
            }

            // ==========================================================
            // 2) Verhältnis PV / Netz
            // ==========================================================
            if ($globalImpTotal == 0.0 && $globalExpTotal > 0.0) {
                // nur Export → PV deckt alles
                $ratio       = 0.0;
                $pvCoversAll = true;

            } elseif ($globalExpTotal == 0.0 && $globalImpTotal > 0.0) {
                // nur Import → Netz deckt alles
                $ratio       = 0.0;
                $pvCoversAll = false;

            } elseif ($globalImpTotal <= $globalExpTotal) {
                // PV produziert genug
                $ratio       = $globalExpTotal ? ($globalImpTotal / $globalExpTotal) : 0.0;
                $pvCoversAll = true;

            } else {
                // Netzbezug notwendig
                $ratio       = $globalImpTotal ? ($globalExpTotal / $globalImpTotal) : 0.0;
                $pvCoversAll = false;
            }

            // ==========================================================
            // 3) PRO USER VERTEILEN
            // ==========================================================
            foreach ($globalSlot as $name => $v) {
                $userId = $v['user_id'];

                // Falls User nicht im Cache ist → ignorieren
                if (!isset($this->powerCostCache[$userId][$name])) {
                    continue;
                }

                $imp = $v['imp'];
                $exp = $v['exp'];

                // Totale speichern
                $this->powerCostCache[$userId][$name]['imp'] += $imp;
                $this->powerCostCache[$userId][$name]['exp'] += $exp;

                // PV deckt alles
                if ($pvCoversAll) {
                    $this->powerCostCache[$userId][$name]['solar_bezug']      += $imp;
                    $this->powerCostCache[$userId][$name]['solareinspeisung'] += (1 - $ratio) * $exp;
                    $this->powerCostCache[$userId][$name]['solarverkauf']     += $ratio * $exp;

                    if ($pSolar !== null) {
                        $this->powerCostCache[$userId][$name]['cost_solar'] += ($imp * $pSolar) / 100.0;
                    }
                    if ($pFeed !== null) {
                        $this->powerCostCache[$userId][$name]['rev_feedin'] += ((1 - $ratio) * $exp * $pFeed) / 100.0;
                        $this->powerCostCache[$userId][$name]['rev_zev']    += ($ratio * $exp * $pSolar) / 100.0;
                    }

                // Netz deckt einen Teil
                } else {
                    $this->powerCostCache[$userId][$name]['solar_bezug']  += $ratio * $imp;
                    $this->powerCostCache[$userId][$name]['netz_bezug']   += (1 - $ratio) * $imp;
                    $this->powerCostCache[$userId][$name]['solarverkauf'] += $exp;

                    if ($pGrid !== null) {
                        $this->powerCostCache[$userId][$name]['cost_grid'] += ((1 - $ratio) * $imp * $pGrid) / 100.0;
                    }
                    if ($pSolar !== null) {
                        $this->powerCostCache[$userId][$name]['cost_solar'] += ($ratio * $imp * $pSolar) / 100.0;
                    }
                    if ($pFeed !== null) {
                        $this->powerCostCache[$userId][$name]['rev_zev'] += ($exp * $pSolar) / 100.0;
                    }
                }
            }
        }

    }
    private function GetCalculatedPowerCosts($userId)
    {
        $html = "
            <style>
                table.powercost {
                    width: 100%;
                    border-collapse: collapse;
                    font-size: 10px;
                }
                table.powercost th {
                    background-color: #444;
                    color: white;
                    padding: 4px;
                    text-align: center;
                    font-weight: bold;
                    border: 1px solid #777;
                }
                table.powercost td {
                    padding: 3px 4px;
                    border: 1px solid #ccc;
                }
                .row-even { background-color: #f7f7f7; }
                .row-odd  { background-color: #ffffff; }
                .row-empty { background-color: #e0e0e0; height: 5px; }

                /* Neue Formatierungen */
                .num {
                    text-align: right;
                    font-family: monospace;
                    width: 90px;
                }
                .subtotal-row {
                    border-top: 1px solid black;
                    font-weight: bold;
                }
                .total-row {
                    border-top: 3px double black;
                    font-weight: bold;
                    background-color: #ddd;
                }
            </style>

            <table class='powercost'>
            <tr>
                <th>ID</th>
                <th>Import (kWh)</th>
                <th>Export (kWh)</th>
                <th>ZEV-Haus (kWh)</th>
                <th>Netz-Haus (kWh)</th>
                <th>Solar-Netz (kWh)</th>
                <th>Solar-ZEV (kWh)</th>
                <th>Kauf Solar (CHF)</th>
                <th>Kauf Netz (CHF)</th>
                <th>Verkauf Netz(CHF)</th>
                <th>Verkauf ZEV(CHF)</th>
                <th>Total CHF</th>
            </tr>";

        if (empty($this->powerCostCache) || !isset($this->powerCostCache[$userId])) {
            $html .= "<tr><td colspan='12' align='center'>Keine Stromzähler für diesen Benutzer</td></tr></table>";
            return ['html' => $html, 'sum' => 0.0];
        }

        $sum = 0.0;
        $rowIndex = 0;

        foreach ($this->powerCostCache[$userId] as $name => $a) {

            $subtotal = $a['cost_grid'] + $a['cost_solar'] - ($a['rev_feedin'] + $a['rev_zev']);
            $sum += $subtotal;

            $rowClass = ($rowIndex % 2 === 0) ? "row-even" : "row-odd";
            $rowIndex++;

            // Datenzeile
            $html .= "<tr class='{$rowClass}'>
                <td>{$a['name']}</td>
                <td class='num' style='background-color:#f0f0f0; text-align: right;'>" . number_format($a['imp'], 3, '.', "'") . "</td>
                <td class='num' text-align='right'>" . number_format($a['exp'], 3, '.', "'") . "</td>
                <td class='num' text-align='right'>" . number_format($a['solar_bezug'], 3, '.', "'") . "</td>
                <td class='num' text-align='right'>" . number_format($a['netz_bezug'], 3, '.', "'") . "</td>
                <td class='num' text-align='right'>" . number_format($a['solareinspeisung'], 3, '.', "'") . "</td>
                <td class='num' text-align='right'>" . number_format($a['solarverkauf'], 3, '.', "'") . "</td>
                <td class='num' text-align='right'>" . number_format($a['cost_solar'], 2, '.', "'") . "</td>
                <td class='num' text-align='right'>" . number_format($a['cost_grid'], 2, '.', "'") . "</td>
                <td class='num' text-align='right'>" . number_format($a['rev_feedin'], 2, '.', "'") . "</td>
                <td class='num' text-align='right'>" . number_format($a['rev_zev'], 2, '.', "'") . "</td>
                <td class='num underline' text-align='right'><strong>" . number_format($subtotal, 2, '.', "'") . "</strong></td>
            </tr>";

            // Leerzeile
            $html .= "<tr class='row-empty'><td colspan='12'></td></tr>";
        }

        // Gesamttotal
        $html .= "
            <tr class='total-row'>
                <td colspan='11' text-align='right'><b>Total</b></td>
                    <td align='right'></td>
                    <td align='right'></td>
                    <td align='right'></td>
                    <td align='right'></td>
                    <td align='right'></td>
                    <td align='right'></td>
                    <td align='right'></td>
                    <td align='right'></td>
                    <td align='right'></td>
                    <td align='right'></td>
                    <td class='num double-underline' text-align='right'><strong>" . number_format($sum, 2, '.', "'") . "</strong></td>
            </tr>
            </table>";

        return ['html' => $html, 'sum' => $sum];
    }

    // ====================== Nebenkosten Wasser/Wärme ======================

    private function CalculateAdditionalCosts($waterMeters, $tariffs, $userId, $from, $to)
    {
        $html = "
<table border='1' cellspacing='0' cellpadding='2' width='100%' style='font-size:4px;'>
<tr style='background-color:#f0f0f0;'>
    <th>ID</th>
    <th>Typ</th>
    <th>Datum von</th>
    <th>Datum bis</th>
    <th>Zähler Start</th>
    <th>Zähler Ende</th>
    <th>Verbrauch</th>
    <th>Tarif</th>
    <th>Kosten CHF</th>
</tr>";

        $total       = 0.0;
        $usedTariffs = [];

        foreach ($waterMeters as $m) {
            if ($m['user_id'] != $userId) {
                continue;
            }
            $type = $m['meter_type'] ?? 'Warmwasser';
            $cost = $this->AddMeterToPDFRow($m, $tariffs, $from, $to, $type);
            $html .= $cost['row'];
            $total += $cost['value'];
            $usedTariffs = array_merge($usedTariffs, $cost['tariffs']);
        }

            $html .= "<tr style='background-color:#f9f9f9; font-weight:bold;'>
                <td colspan='25' align='right'><b>Total</b></td>
                <td align='right'></td>
                <td align='right'></td>
                <td align='right'></td>
                <td align='right'></td>
                <td align='right'></td>
                <td align='right'></td>
                <td align='right'></td>
                <td align='right'><b>CHF " . number_format($total, 2) . ".-</b></td>
            </tr>";

        if (!empty($usedTariffs)) {
            $html .= "<p><strong>Angewendete Nebenkostentarife</strong></p><ul>";
            foreach ($usedTariffs as $t) {
                $html .= "<li>" . date('d.m.Y', $t['start']) . " – " . date('d.m.Y', $t['end']) . " — <strong> " .
                    number_format($t['price'], 2) . " Rp/m3</strong></li>";
            }
            $html .= "</ul><br><hr>";
        }

        return ['html' => $html, 'sum' => $total];
    }

    private function AddMeterToPDFRow($meter, $tariffs, $from, $to, $type)
    {
        $rows        = '';
        $totalCost   = 0.0;
        $usedTariffs = [];
        $varId       = $meter['var_consumption'];

        if (!IPS_VariableExists($varId)) {
            return ['row' => '', 'value' => 0, 'tariffs' => []];
        }

        // Relevante Tarife nach Typ filtern
        $filteredTariffs = array_filter($tariffs, fn($t) =>
            strtolower(trim($t['unit_type'] ?? '')) === strtolower(trim($type))
        );

        $activeTariff = null;
        foreach ($filteredTariffs as $t) {
            $startTs = $this->toUnixTs($t['start'], false);
            $endTs   = $this->toUnixTs($t['end'], true);
            if ($startTs === null || $endTs === null) {
                continue;
            }
            // Tarif überlappt den Abrechnungszeitraum
            if ($endTs < $from || $startTs > $to) {
                continue;
            }
            $activeTariff = [
                'start' => $startTs,
                'end'   => $endTs,
                'price' => (float)$t['price']
            ];
            $usedTariffs[] = $activeTariff;
            break; // erster passender Tarif reicht
        }

        $tariffPrice = $activeTariff ? $activeTariff['price'] : 0.0;

        // Verbrauch = letzter Wert vor/gleich "to" minus letzter Wert vor/gleich "from"
        $startValue = $this->GetValueAt($varId, $from, false);
        $endValue   = $this->GetValueAt($varId, $to, false);

        if ($startValue === null || $endValue === null) {
            return ['row' => '', 'value' => 0, 'tariffs' => []];
        }

        $verbrauch = max(0, $endValue - $startValue);
        $kosten    = round(($tariffPrice / 100) * $verbrauch, 2);
        $totalCost = $kosten;

        $rows .= "<tr>
            <td>{$meter['name']}</td>
            <td>{$type}</td>
            <td align='center'>" . date('d.m.Y', $from) . "</td>
            <td align='center'>" . date('d.m.Y', $to) . "</td>
            <td align='right'>" . number_format($startValue, 2) . "</td>
            <td align='right'>" . number_format($endValue, 2) . "</td>
            <td align='right'>" . number_format($verbrauch, 2) . "</td>
            <td align='right'>" . number_format($tariffPrice, 2) . "</td>
            <td align='right'>" . number_format($kosten, 2) . "</td>
        </tr>";

        if ($rows === '') {
            return ['row' => '', 'value' => 0, 'tariffs' => []];
        }

        return ['row' => $rows, 'value' => $totalCost, 'tariffs' => array_values($usedTariffs)];
    }

    // ====================== Hilfsfunktionen ======================

    private function GetValueAt($varId, $timestamp, $nearestAfter = true)
    {
        $archiveID = @IPS_GetInstanceListByModuleID('{43192F0B-135B-4CE7-A0A7-1475603F3060}')[0];
        if (!$archiveID || !IPS_VariableExists($varId)) {
            return null;
        }

        if ($nearestAfter) {
            // Erster Wert NACH oder GENAU ab Timestamp
            $values = @AC_GetLoggedValues(
                $archiveID,
                $varId,
                $timestamp,      // start
                time(),          // end
                1                // LIMIT
            );
        } else {
            // Letzter Wert DAVOR oder GENAU bis Timestamp
            $values = @AC_GetLoggedValues(
                $archiveID,
                $varId,
                0,               // start
                $timestamp,      // end
                1                // LIMIT
            );
        }

        if (!empty($values)) {
            return (float)$values[0]['Value'];
        }

        // Fallback → Live-Wert
        return (float)GetValue($varId);
    }

    private function getDeltaFromArchive(int $varId, int $tStart, int $tEnd): float
    {
        // Werte holen
        $startValue = $this->GetValueAt($varId, $tStart, false);
        $endValue   = $this->GetValueAt($varId, $tEnd, false);

        if ($startValue === null || $endValue === null) {
            return 0.0;
        }

        // Delta berechnen
        $diff = $endValue - $startValue;

        if ($diff < 0) {
            $diff = 0.0;
        }

        return (float)$diff;
    }

    private function toUnixTs($val, $endOfDay = false)
    {
        if (is_int($val)) {
            return $val;
        }
        if (is_numeric($val)) {
            return (int)$val;
        }

        if (is_string($val)) {
            $s = trim($val);
            if ($s !== '' && $s[0] === '{') {
                $obj = json_decode($s, true);
                if (isset($obj['year'], $obj['month'], $obj['day'])) {
                    $time = $endOfDay ? '23:59:59' : '00:00:00';
                    return strtotime(sprintf(
                        '%04d-%02d-%02d %s',
                        $obj['year'],
                        $obj['month'],
                        $obj['day'],
                        $time
                    ));
                }
            }
            $ts = strtotime($s);
            return $ts === false ? null : $ts;
        }
        return null;
    }

    private function getTariffPriceAt($tariffs, $typeSynonyms, $ts)
    {
        $wanted = array_map('strtolower', $typeSynonyms);
        $cands  = [];

        foreach ($tariffs as $t) {
            $u = strtolower(trim($t['unit_type'] ?? ''));
            if (!in_array($u, $wanted, true)) {
                continue;
            }

            $s = $this->toUnixTs($t['start'], false);
            $e = $this->toUnixTs($t['end'], true);
            if (!$s || !$e) {
                continue;
            }
            if ($s <= $ts && $ts <= $e) {
                $cands[] = (float)$t['price'];
            }
        }

        if (empty($cands)) {
            return null;
        }
        return end($cands);
    }

    private function CollectTariffsForUser($tariffs, $types)
    {
        $result = [];
        $wanted = array_map('strtolower', $types);

        foreach ($tariffs as $t) {
            $type = strtolower(trim($t['unit_type'] ?? ''));
            if (!in_array($type, $wanted, true)) {
                continue;
            }

            $start = $this->toUnixTs($t['start'], false);
            $end   = $this->toUnixTs($t['end'], true);

            $result[] = [
                'start' => $start,
                'end'   => $end,
                'price' => (float)$t['price']
            ];
        }

        return $result;
    }

    private function GetLogoFile()
    {
        $mediaID = (int)$this->ReadPropertyInteger('LogoMediaID');
        if ($mediaID <= 0 || !IPS_MediaExists($mediaID)) {
            return null;
        }

        $media = IPS_GetMedia($mediaID);
        $ext   = 'png';
        if (!empty($media['MediaFile'])) {
            $extFromFile = pathinfo($media['MediaFile'], PATHINFO_EXTENSION);
            if ($extFromFile !== '') {
                $ext = $extFromFile;
            }
        }

        $path = IPS_GetKernelDir() . 'media/logo_' . $mediaID . '.' . $ext;

        // Bild aus der Symcon-Media-Datenbank extrahieren
        $raw = IPS_GetMediaContent($mediaID); // base64
        $bin = base64_decode($raw);
        if ($bin === false) {
            return null;
        }

        file_put_contents($path, $bin);

        return $path;
    }
}
?>