"""
Verbrauchsportal API – Automatisierte Tests
Generiert aus openapi.json v1.0.1

Setup:
    pip install pytest pytest-django

pytest.ini:
    [pytest]
    DJANGO_SETTINGS_MODULE = verbrauchsportal.settings

Ausführen:
    pytest tests/test_api.py -v
    pytest tests/test_api.py -v -k "real_estate"   # nur eine Gruppe
"""

import hashlib
from app_admin.models import AdminToken, AdminUser

import pytest
from rest_framework.test import APIClient

pytestmark = pytest.mark.django_db 

# ── Konfiguration ──────────────────────────────────────────────────────────────
BEARER_TOKEN = "e5e24cd25bde5d04f7765ac5f1525173be07ded23a54e073ae4775a8f8850a03"  # ← Token aus dem Django Admin eintragen

BASE_URL = "http://localhost:8000"

# Test-IDs (werden bei PUT-Tests erstellt, bei Cleanup gelöscht)
TEST_REID   = 9999
TEST_REUID  = 9999
TEST_PERSONID = 9999
TEST_MIETVID  = 9999
TEST_REF_VERR_ID  = 9999
TEST_REF_VERD_ID  = 9999
TEST_VERBR_ID     = 9999
TEST_VERBRD_ID    = 9999


# ── Fixtures ───────────────────────────────────────────────────────────────────

@pytest.fixture
def admin_user(db):
    user = AdminUser.objects.create(
        email='test@admin.de',
        name='Test Admin',
        is_staff=True,
        is_active=True,
    )
    return user

@pytest.fixture
def admin_token(admin_user):
    token = AdminToken.objects.create(
        user=admin_user,
        key_hash=hashlib.sha256(BEARER_TOKEN.encode()).hexdigest()
    )
    return token

@pytest.fixture
def client(admin_token):  # ← admin_token sorgt dafür dass Token in DB existiert
    c = APIClient()
    c.credentials(HTTP_AUTHORIZATION=f'Bearer {BEARER_TOKEN}')
    return c

@pytest.fixture
def anon_client():
    return APIClient()


# ── Auth-Tests ─────────────────────────────────────────────────────────────────

class TestAuth:
    def test_kein_token_liefert_401(self, anon_client):
        response = anon_client.get('/api/res')
        assert response.status_code == 401

    def test_falscher_token_liefert_401(self):
        c = APIClient()
        c.credentials(HTTP_AUTHORIZATION='Bearer ungueltigertoken123')
        response = c.get('/api/res')
        assert response.status_code == 401

    def test_token_format_ohne_bearer_liefert_401(self):
        c = APIClient()
        c.credentials(HTTP_AUTHORIZATION=f'Token {BEARER_TOKEN}')
        response = c.get('/api/res')
        assert response.status_code == 401


# ── RealEstate  GET /api/res ───────────────────────────────────────────────────

class TestRealEstate:
    def test_get_liste(self, client):
        response = client.get('/api/res')
        assert response.status_code == 200
        assert isinstance(response.data, list)

    def test_get_liste_struktur(self, client):
        response = client.get('/api/res')
        assert response.status_code == 200
        if len(response.data) > 0:
            item = response.data[0]
            assert 'REID'        in item
            assert 'Street'      in item
            assert 'HouseNumber' in item
            assert 'PostalCode'  in item
            assert 'City'        in item

    def test_put_erstellen(self, client):
        response = client.put('/api/res', {
            "REID":        TEST_REID,
            "Street":      "Teststraße",
            "HouseNumber": "99",
            "PostalCode":  "12345",
            "City":        "Teststadt"
        }, format='json')
        assert response.status_code in [200, 201]

    def test_put_fehlende_pflichtfelder(self, client):
        response = client.put('/api/res', {
            "REID": TEST_REID
            # Street, HouseNumber, PostalCode, City fehlen
        }, format='json')
        assert response.status_code == 400

    def test_put_update(self, client):
        """Gleiche REID nochmal – sollte updaten, nicht doppelt anlegen."""
        response = client.put('/api/res', {
            "REID":        TEST_REID,
            "Street":      "Geänderte Straße",
            "HouseNumber": "1",
            "PostalCode":  "12345",
            "City":        "Teststadt"
        }, format='json')
        assert response.status_code in [200, 201]


# ── RealEstateUnit  GET+PUT /api/reus ─────────────────────────────────────────

class TestRealEstateUnit:
    def test_get_liste(self, client):
        response = client.get('/api/reus')
        assert response.status_code == 200
        assert isinstance(response.data, list)

    def test_get_liste_struktur(self, client):
        response = client.get('/api/reus')
        assert response.status_code == 200
        if len(response.data) > 0:
            item = response.data[0]
            assert 'REUID'   in item
            assert 'REID'    in item
            assert 'REUDesc' in item
            assert 'REUCID'  in item

    def test_put_bulk_erstellen(self, client):
        response = client.put('/api/reus', [
            {"REUID": TEST_REUID,     "REID": TEST_REID, "REUDesc": "Test OG links",  "REUCID": 1},
            {"REUID": TEST_REUID + 1, "REID": TEST_REID, "REUDesc": "Test EG rechts", "REUCID": 1},
        ], format='json')
        assert response.status_code in [200, 201]

    def test_put_einzeln_erstellen(self, client):
        response = client.put('/api/reus', {
            "REUID": TEST_REUID + 2, "REID": TEST_REID,
            "REUDesc": "Einzelne Einheit", "REUCID": 1
        }, format='json')
        assert response.status_code in [200, 201]

    def test_put_fehlende_pflichtfelder(self, client):
        response = client.put('/api/reus', [
            {"REUID": TEST_REUID}  # REID, REUDesc, REUCID fehlen
        ], format='json')
        assert response.status_code == 400


# ── User  GET+PUT /api/users ───────────────────────────────────────────────────

class TestUser:
    def test_get_liste(self, client):
        response = client.get('/api/users')
        assert response.status_code == 200
        assert isinstance(response.data, list)

    def test_get_liste_struktur(self, client):
        response = client.get('/api/users')
        assert response.status_code == 200
        if len(response.data) > 0:
            item = response.data[0]
            assert 'PersonenID' in item
            assert 'email'      in item

    def test_put_erstellen(self, client):
        response = client.put('/api/users', {
            "PersonenID": TEST_PERSONID,
            "lastname":   "Testmann",
            "firstname":  "Test",
            "email":      "test@test.de",
            "VISysEMailPreference": 1,
            "SalutationID": 1
        }, format='json')
        assert response.status_code in [200, 201]

    def test_put_ohne_passwort(self, client):
        """Ohne Passwort soll ein zufälliges generiert werden."""
        response = client.put('/api/users', {
            "PersonenID": TEST_PERSONID + 1,
            "email":      "autogen@test.de",
        }, format='json')
        assert response.status_code in [200, 201]

    def test_put_fehlende_pflichtfelder(self, client):
        response = client.put('/api/users', {
            "lastname": "Nurname"
            # PersonenID und email fehlen
        }, format='json')
        assert response.status_code == 400


# ── MietV  GET /api/mietvs/{reid}  +  PUT /api/mietvs ────────────────────────

class TestMietV:
    def test_get_mit_reid(self, client):
        response = client.get(f'/api/mietvs/{TEST_REID}')
        assert response.status_code in [200, 404]

    def test_get_struktur(self, client):
        response = client.get(f'/api/mietvs/{TEST_REID}')
        if response.status_code == 200 and len(response.data) > 0:
            item = response.data[0]
            assert 'MietVID'           in item
            assert 'REUID'             in item
            assert 'MieterID'          in item
            assert 'ContractValidFrom' in item

    def test_put_erstellen(self, client):
        response = client.put('/api/mietvs', {
            "MietVID":           TEST_MIETVID,
            "REUID":             TEST_REUID,
            "MieterID":          TEST_PERSONID,
            "ContractValidFrom": "2024-01-01",
            "ContractValidUntil": None
        }, format='json')
        assert response.status_code in [200, 201]

    def test_put_fehlende_pflichtfelder(self, client):
        response = client.put('/api/mietvs', {
            "MietVID": TEST_MIETVID
            # REUID, MieterID, ContractValidFrom fehlen
        }, format='json')
        assert response.status_code == 400


# ── RefVerbrauchRahmen  PUT /api/refverbrrahmen ────────────────────────────────

class TestRefVerbrauchRahmen:
    def test_put_erstellen(self, client):
        response = client.put('/api/refverbrrahmen', {
            "VISysRefVerbrID":      TEST_REF_VERR_ID,
            "REID":                 TEST_REID,
            "Jahr":                 2023,
            "VISysVerbrauchsArtID": 1
        }, format='json')
        assert response.status_code in [200, 201]

    def test_put_fehlende_pflichtfelder(self, client):
        response = client.put('/api/refverbrrahmen', {
            "VISysRefVerbrID": TEST_REF_VERR_ID
        }, format='json')
        assert response.status_code == 400


# ── RefVerbrauchsDaten  PUT /api/refverbrdaten ────────────────────────────────

class TestRefVerbrauchsDaten:
    def test_put_bulk_erstellen(self, client):
        response = client.put('/api/refverbrdaten', [{
            "RefVerBrDatID":     TEST_REF_VERD_ID,
            "RefVerBrSD":        "2023-01-01",
            "RefVerBrED":        "2023-12-31",
            "RefVerBrWert":      12500.5,
            "RefVerBrID":        TEST_REF_VERR_ID,
            "RefVerBrWertNormA": 11800.0
        }], format='json')
        assert response.status_code in [200, 201]

    def test_put_einzeln(self, client):
        response = client.put('/api/refverbrdaten', {
            "RefVerBrDatID": TEST_REF_VERD_ID + 1,
            "RefVerBrSD":    "2023-01-01",
            "RefVerBrED":    "2023-06-30",
            "RefVerBrWert":  6000.0,
            "RefVerBrID":    TEST_REF_VERR_ID
        }, format='json')
        assert response.status_code in [200, 201]

    def test_put_fehlende_pflichtfelder(self, client):
        response = client.put('/api/refverbrdaten', [{
            "RefVerBrDatID": TEST_REF_VERD_ID
        }], format='json')
        assert response.status_code == 400


# ── VerbrauchRahmen  PUT /api/verbrrahmen ─────────────────────────────────────

class TestVerbrauchRahmen:
    def test_put_bulk_erstellen(self, client):
        response = client.put('/api/verbrrahmen', [{
            "VISysVerbrauchsID":    TEST_VERBR_ID,
            "MietVID":              TEST_MIETVID,
            "REUDesc":              "Test Wohnung",
            "Jahr":                 2023,
            "VISysVerbrauchsArtID": 1
        }], format='json')
        assert response.status_code in [200, 201]

    def test_put_fehlende_pflichtfelder(self, client):
        response = client.put('/api/verbrrahmen', [{
            "VISysVerbrauchsID": TEST_VERBR_ID
        }], format='json')
        assert response.status_code == 400

    def test_put_bulk_fehler_im_zweiten_datensatz(self, client):
        """Regression: Fehler ausserhalb des ersten Datensatzes ergab HTTP 500."""
        response = client.put('/api/verbrrahmen', [
            {
                "VISysVerbrauchsID":    TEST_VERBR_ID,
                "MietVID":              TEST_MIETVID,
                "Jahr":                 2023,
                "VISysVerbrauchsArtID": 1
            },
            {
                "VISysVerbrauchsID": TEST_VERBR_ID + 1
            },
        ], format='json')
        assert response.status_code == 400


# ── VerbrauchsDaten  POST+PUT /api/verbrdaten ─────────────────────────────────

class TestVerbrauchsDaten:
    PAYLOAD = [{
        "VerBrDatID":     TEST_VERBRD_ID,
        "VerBrSD":        "2023-01-01",
        "VerBrED":        "2023-03-31",
        "VerBrWert":      3100.25,
        "VerBrID":        TEST_VERBR_ID,
        "VerBrWertNormA": 2950.0
    }]

    def test_post_erstellen(self, client):
        response = client.post('/api/verbrdaten', self.PAYLOAD, format='json')
        assert response.status_code in [200, 201]

    def test_put_upsert(self, client):
        response = client.put('/api/verbrdaten', self.PAYLOAD, format='json')
        assert response.status_code in [200, 201]

    def test_post_fehlende_pflichtfelder(self, client):
        response = client.post('/api/verbrdaten', [{
            "VerBrDatID": TEST_VERBRD_ID
        }], format='json')
        assert response.status_code == 400

    def test_put_fehlende_pflichtfelder(self, client):
        response = client.put('/api/verbrdaten', [{
            "VerBrDatID": TEST_VERBRD_ID
        }], format='json')
        assert response.status_code == 400


# ── Me  GET /api/me ───────────────────────────────────────────────────────────

class TestMe:
    def test_get_aktueller_user(self, client):
        response = client.get('/api/me')
        assert response.status_code == 200

    def test_get_struktur(self, client):
        response = client.get('/api/me')
        assert response.status_code == 200
        # Mindestens eines der erwarteten Felder muss vorhanden sein
        data = response.data
        assert any(key in data for key in ['ApiUserID', 'ApiUserName', 'ApiUserEMail'])

    def test_get_ohne_token(self, anon_client):
        response = anon_client.get('/api/me')
        assert response.status_code == 401