#!/usr/bin/env python3
"""Regressionstest für shell_beleg_parser.py gegen zehn echte Shell-eReceipts.

Die PDFs in belege/ sind reale, vom Nutzer bereitgestellte Tankbelege aus
vier verschiedenen Stationen (Ingolstadt/Zrenner, Rain am Lech/Bauch,
Ansbach/Sengül, Königsbronn/Mogler) und decken damit die tatsächlich
beobachtete Formatvielfalt ab, nicht nur eine angenommene Struktur:
  - Markenzeile: "SHELL STATION" / "Shell Station" / "Shell-Station"
  - Rabattbezeichnung: "V-Power Smart Deal" / "ClubSmartRabatt"
  - POS-Zeile: mit und ohne "68002-"-Präfix vor der Stations-ID
  - unterschiedliche Fußzeilen-Länge/-Inhalte

Aufruf: python3 tests/belegparser/test_shell_beleg_parser.py
(braucht pypdf; in Home Assistant bringt die Integration es über
manifest.json mit, hier reicht ein "pip install pypdf")
"""

import os
import sys
import unittest

_HIER = os.path.dirname(os.path.abspath(__file__))
_BELEGE = os.path.join(_HIER, "belege")
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(_HIER)), "custom_components", "audi_dashboard"))

import shell_beleg_parser as p  # noqa: E402


def _parsen_datei(dateiname):
    pfad = os.path.join(_BELEGE, dateiname)
    return p._parsen(p._text_aus_pdf(pfad))


class AlleBelegeParsenOhneFehler(unittest.TestCase):
    """Jeder der zehn echten Belege muss ohne Exception durchlaufen und
    strukturell plausible Werte liefern - das ist der eigentliche Zweck
    dieser Suite: künftige Regex-Änderungen dürfen keinen der bekannten
    realen Belegtypen mehr brechen."""

    @classmethod
    def setUpClass(cls):
        cls.dateien = sorted(f for f in os.listdir(_BELEGE) if f.endswith(".pdf"))
        cls.ergebnisse = {f: _parsen_datei(f) for f in cls.dateien}

    def test_zehn_belege_gefunden(self):
        self.assertEqual(len(self.dateien), 10, self.dateien)

    def test_pflichtfelder_gesetzt(self):
        pflichtfelder = [
            "receipt_key", "receipt_no", "ts", "station_id", "station_name",
            "station_address", "article_no", "product_name", "fuel_type",
            "liters", "list_price_per_l", "fuel_total_eur",
            "receipt_total_eur", "net_eur", "vat_eur",
        ]
        for datei, d in self.ergebnisse.items():
            for feld in pflichtfelder:
                with self.subTest(datei=datei, feld=feld):
                    self.assertIsNotNone(d[feld], f"{feld} fehlt in {datei}")

    def test_betraege_plausibel(self):
        for datei, d in self.ergebnisse.items():
            with self.subTest(datei=datei):
                self.assertGreater(d["liters"], 0)
                self.assertGreater(d["list_price_per_l"], 0)
                self.assertGreater(d["fuel_total_eur"], 0)
                # Netto + MwSt muss dem Bruttobetrag entsprechen (Rundung: 1 Cent)
                self.assertAlmostEqual(d["net_eur"] + d["vat_eur"], d["receipt_total_eur"], delta=0.01)
                # Gesamtbetrag der Position == Bruttobetrag der Steuerzeile
                self.assertAlmostEqual(d["fuel_total_eur"], d["receipt_total_eur"], delta=0.01)
                if d["discount"] is not None:
                    self.assertGreater(d["discount"], 0)
                    # Rabatt darf den Bruttobetrag nicht übersteigen
                    self.assertLess(d["discount"], d["fuel_total_eur"])

    def test_receipt_key_eindeutig(self):
        schluessel = [d["receipt_key"] for d in self.ergebnisse.values()]
        self.assertEqual(len(schluessel), len(set(schluessel)), schluessel)

    def test_bekannte_stationen(self):
        # Vier verschiedene Standorte in den zehn Belegen - stellt sicher, dass
        # die Stationserkennung nicht zufällig nur für einen Beleg passt.
        # Anzeigeformat seit 2026-08-16: "Marke, Straße, Ort" statt des reinen
        # Betreibernamens ("A. Zrenner GmbH" o. ä.) - der Betreiber sagt beim
        # Durchblättern der Tankvorgänge weniger als Marke und Ort.
        namen = {d["station_name"] for d in self.ergebnisse.values()}
        erwartet = {
            "Shell, Pascalstr. 8, Ingolstadt",
            "Shell, Münchener Str.15a, Ingolstadt",
            "Shell, Nürnberger Str.74, Ansbach",
            "Shell, Heidenheimerstr.6, Königsbronn",
        }
        self.assertEqual(namen, erwartet)

    def test_rabatt_label_unabhaengig(self):
        # e-receipt7.pdf nutzt "ClubSmartRabatt" statt "V-Power Smart Deal" -
        # die Rabatterkennung darf nicht am Label hängen, nur am Betragsmuster.
        d = self.ergebnisse["e-receipt7.pdf"]
        self.assertAlmostEqual(d["discount"], 6.95, delta=0.001)
        self.assertAlmostEqual(d["discount_per_l"], 0.18, delta=0.001)

    def test_stichproben_werte(self):
        # Punktuelle Kontrolle einzelner, von Hand aus dem Beleg abgelesener
        # Werte - fängt stille Verschiebungen (z.B. falsche Regex-Gruppe) ab,
        # die die reinen Plausibilitätschecks oben nicht erkennen würden.
        stichproben = {
            "e-receipt.pdf": dict(liters=42.15, fuel_total_eur=78.78, discount=11.80, station_id="0000007770"),
            "e-receipt3.pdf": dict(liters=21.73, fuel_total_eur=44.53, discount=6.08, station_id="0000000456"),
            "e-receipt5.pdf": dict(liters=47.76, fuel_total_eur=79.23, discount=12.90, station_id="0000002227"),
            "e-receipt9.pdf": dict(liters=51.59, fuel_total_eur=85.59, discount=13.41, station_id="0000002103"),
        }
        for datei, erwartet in stichproben.items():
            d = self.ergebnisse[datei]
            with self.subTest(datei=datei):
                self.assertAlmostEqual(d["liters"], erwartet["liters"], delta=0.001)
                self.assertAlmostEqual(d["fuel_total_eur"], erwartet["fuel_total_eur"], delta=0.001)
                self.assertAlmostEqual(d["discount"], erwartet["discount"], delta=0.001)
                self.assertEqual(d["station_id"], erwartet["station_id"])


class BelegOhneRabatt(unittest.TestCase):
    """SmartDeal/ClubSmart ist optional - nicht jeder Tankvorgang hat einen
    Rabatt. Simuliert durch Entfernen der Rabattzeilen aus einem echten
    Beleg, da keiner der zehn realen Belege rabattfrei war."""

    def test_ohne_rabatt_bleibt_alles_andere_korrekt(self):
        text = p._text_aus_pdf(os.path.join(_BELEGE, "e-receipt.pdf"))
        ohne_rabatt = "\n".join(
            z for z in text.split("\n")
            if "Smart Deal" not in z and "EUR/Liter" not in z
        )
        d = p._parsen(ohne_rabatt)
        self.assertIsNone(d["discount"])
        self.assertIsNone(d["discount_per_l"])
        self.assertAlmostEqual(d["fuel_total_eur"], 78.78, delta=0.001)
        self.assertAlmostEqual(d["liters"], 42.15, delta=0.001)


if __name__ == "__main__":
    unittest.main(verbosity=2)
