<?php

declare(strict_types=1);

namespace OCA\Mitgliederverwaltung\Tests\Unit;

use OCA\Mitgliederverwaltung\Db\Address;
use OCA\Mitgliederverwaltung\Db\AuditLog;
use OCA\Mitgliederverwaltung\Db\Email;
use OCA\Mitgliederverwaltung\Db\Family;
use OCA\Mitgliederverwaltung\Db\FeeRecord;
use OCA\Mitgliederverwaltung\Db\FeeRule;
use OCA\Mitgliederverwaltung\Db\Injury;
use OCA\Mitgliederverwaltung\Db\Lager;
use OCA\Mitgliederverwaltung\Db\LagerTeilnehmer;
use OCA\Mitgliederverwaltung\Db\Member;
use OCA\Mitgliederverwaltung\Db\Permission;
use OCA\Mitgliederverwaltung\Db\Phone;
use OCA\Mitgliederverwaltung\Db\SavedQuery;
use OCA\Mitgliederverwaltung\Db\Stufe;
use OCA\Mitgliederverwaltung\Db\StufeHistory;
use PHPUnit\Framework\TestCase;

class EntityTest extends TestCase {

    // ── Member ──────────────────────────────────────────────────────

    public function testMemberDefaultValues(): void {
        $member = new Member();
        $this->assertSame('', $member->getVorname());
        $this->assertSame('', $member->getNachname());
        $this->assertNull($member->getGeburtsdatum());
        $this->assertNull($member->getGeschlecht());
        $this->assertSame('mitglied', $member->getRolle());
        $this->assertNull($member->getStufeId());
        $this->assertSame('', $member->getEintritt());
        $this->assertNull($member->getAustritt());
        $this->assertSame('aktiv', $member->getStatus());
        $this->assertNull($member->getAllergienEncrypted());
        $this->assertNull($member->getNotizen());
        $this->assertNull($member->getZusatzNotizen());
        $this->assertNull($member->getKvTyp());
        $this->assertNull($member->getKvName());
        $this->assertNull($member->getFamilyId());
        $this->assertNull($member->getFrozenFeeRate());
        $this->assertNull($member->getCalendarEventUri());
        $this->assertNull($member->getContactVcardUri());
        $this->assertSame('', $member->getCreatedAt());
        $this->assertSame('', $member->getUpdatedAt());
        $this->assertNull($member->getDeletedAt());
        $this->assertNull($member->getEinwilligungDatum());
    }

    public function testMemberGettersSetters(): void {
        $member = new Member();
        $member->setId(1);
        $member->setVorname('Max');
        $member->setNachname('Mustermann');
        $member->setGeburtsdatum('2010-05-15');
        $member->setGeschlecht('maennlich');
        $member->setRolle('leiter');
        $member->setStufeId(3);
        $member->setEintritt('2020-01-01');
        $member->setAustritt('2025-12-31');
        $member->setStatus('inaktiv');
        $member->setAllergienEncrypted('encrypted_data');
        $member->setNotizen('Some notes');
        $member->setZusatzNotizen('Extra notes');
        $member->setKvTyp('gesetzlich');
        $member->setKvName('AOK');
        $member->setFamilyId(5);
        $member->setFrozenFeeRate('95.50');
        $member->setCalendarEventUri('cal-uri');
        $member->setContactVcardUri('vcard-uri');
        $member->setCreatedAt('2020-01-01 00:00:00');
        $member->setUpdatedAt('2025-06-15 12:00:00');
        $member->setDeletedAt('2025-12-31 23:59:59');
        $member->setEinwilligungDatum('2020-01-15');

        $this->assertSame(1, $member->getId());
        $this->assertSame('Max', $member->getVorname());
        $this->assertSame('Mustermann', $member->getNachname());
        $this->assertSame('2010-05-15', $member->getGeburtsdatum());
        $this->assertSame('maennlich', $member->getGeschlecht());
        $this->assertSame('leiter', $member->getRolle());
        $this->assertSame(3, $member->getStufeId());
        $this->assertSame('2020-01-01', $member->getEintritt());
        $this->assertSame('2025-12-31', $member->getAustritt());
        $this->assertSame('inaktiv', $member->getStatus());
        $this->assertSame('encrypted_data', $member->getAllergienEncrypted());
        $this->assertSame('Some notes', $member->getNotizen());
        $this->assertSame('Extra notes', $member->getZusatzNotizen());
        $this->assertSame('gesetzlich', $member->getKvTyp());
        $this->assertSame('AOK', $member->getKvName());
        $this->assertSame(5, $member->getFamilyId());
        $this->assertSame('95.50', $member->getFrozenFeeRate());
        $this->assertSame('cal-uri', $member->getCalendarEventUri());
        $this->assertSame('vcard-uri', $member->getContactVcardUri());
        $this->assertSame('2020-01-01 00:00:00', $member->getCreatedAt());
        $this->assertSame('2025-06-15 12:00:00', $member->getUpdatedAt());
        $this->assertSame('2025-12-31 23:59:59', $member->getDeletedAt());
        $this->assertSame('2020-01-15', $member->getEinwilligungDatum());
    }

    public function testMemberJsonSerialize(): void {
        $member = new Member();
        $member->setId(1);
        $member->setVorname('Max');
        $member->setNachname('Mustermann');
        $member->setGeburtsdatum('2010-05-15');
        $member->setRolle('mitglied');
        $member->setEintritt('2020-01-01');
        $member->setStatus('aktiv');
        $member->setCreatedAt('2020-01-01 00:00:00');
        $member->setUpdatedAt('2020-01-01 00:00:00');

        $json = $member->jsonSerialize();

        $this->assertSame(1, $json['id']);
        $this->assertSame('Max', $json['vorname']);
        $this->assertSame('Mustermann', $json['nachname']);
        $this->assertSame('2010-05-15', $json['geburtsdatum']);
        $this->assertSame('mitglied', $json['rolle']);
        $this->assertSame('aktiv', $json['status']);
        $this->assertNull($json['geschlecht']);
        $this->assertNull($json['stufeId']);
        $this->assertNull($json['austritt']);
        $this->assertNull($json['familyId']);
        $this->assertArrayHasKey('allergienEncrypted', $json);
        $this->assertArrayHasKey('notizen', $json);
        $this->assertArrayHasKey('zusatzNotizen', $json);
        $this->assertArrayHasKey('kvTyp', $json);
        $this->assertArrayHasKey('kvName', $json);
        $this->assertArrayHasKey('frozenFeeRate', $json);
        $this->assertArrayHasKey('calendarEventUri', $json);
        $this->assertArrayHasKey('contactVcardUri', $json);
        $this->assertArrayHasKey('deletedAt', $json);
        $this->assertArrayHasKey('einwilligungDatum', $json);
    }

    // ── Family ──────────────────────────────────────────────────────

    public function testFamilyDefaultValues(): void {
        $family = new Family();
        $this->assertSame('', $family->getName());
        $this->assertNull($family->getKontoinhaberEncrypted());
        $this->assertNull($family->getIbanEncrypted());
        $this->assertNull($family->getBic());
        $this->assertNull($family->getKreditinstitut());
        $this->assertSame('', $family->getCreatedAt());
        $this->assertSame('', $family->getUpdatedAt());
    }

    public function testFamilyGettersSetters(): void {
        $family = new Family();
        $family->setId(1);
        $family->setName('Mustermann');
        $family->setKontoinhaberEncrypted('encrypted_holder');
        $family->setIbanEncrypted('encrypted_iban');
        $family->setBic('COBADEFFXXX');
        $family->setKreditinstitut('Commerzbank');
        $family->setCreatedAt('2020-01-01 00:00:00');
        $family->setUpdatedAt('2025-06-15 12:00:00');

        $this->assertSame(1, $family->getId());
        $this->assertSame('Mustermann', $family->getName());
        $this->assertSame('encrypted_holder', $family->getKontoinhaberEncrypted());
        $this->assertSame('encrypted_iban', $family->getIbanEncrypted());
        $this->assertSame('COBADEFFXXX', $family->getBic());
        $this->assertSame('Commerzbank', $family->getKreditinstitut());
        $this->assertSame('2020-01-01 00:00:00', $family->getCreatedAt());
        $this->assertSame('2025-06-15 12:00:00', $family->getUpdatedAt());
    }

    public function testFamilyJsonSerialize(): void {
        $family = new Family();
        $family->setId(1);
        $family->setName('Mustermann');
        $family->setCreatedAt('2020-01-01');
        $family->setUpdatedAt('2020-01-01');

        $json = $family->jsonSerialize();

        $this->assertSame(1, $json['id']);
        $this->assertSame('Mustermann', $json['name']);
        $this->assertArrayHasKey('kontoinhaberEncrypted', $json);
        $this->assertArrayHasKey('ibanEncrypted', $json);
        $this->assertArrayHasKey('bic', $json);
        $this->assertArrayHasKey('kreditinstitut', $json);
        $this->assertArrayHasKey('createdAt', $json);
        $this->assertArrayHasKey('updatedAt', $json);
    }

    // ── Address ─────────────────────────────────────────────────────

    public function testAddressDefaultValues(): void {
        $address = new Address();
        $this->assertSame(0, $address->getMemberId());
        $this->assertNull($address->getLabel());
        $this->assertSame('', $address->getStrasse());
        $this->assertSame('', $address->getPlz());
        $this->assertSame('', $address->getOrt());
        $this->assertSame('Deutschland', $address->getLand());
        $this->assertFalse($address->getIsPrimary());
    }

    public function testAddressGettersSetters(): void {
        $address = new Address();
        $address->setId(1);
        $address->setMemberId(10);
        $address->setLabel('Hauptadresse');
        $address->setStrasse('Musterstrasse 1');
        $address->setPlz('12345');
        $address->setOrt('Musterstadt');
        $address->setLand('Oesterreich');
        $address->setIsPrimary(true);

        $this->assertSame(1, $address->getId());
        $this->assertSame(10, $address->getMemberId());
        $this->assertSame('Hauptadresse', $address->getLabel());
        $this->assertSame('Musterstrasse 1', $address->getStrasse());
        $this->assertSame('12345', $address->getPlz());
        $this->assertSame('Musterstadt', $address->getOrt());
        $this->assertSame('Oesterreich', $address->getLand());
        $this->assertTrue($address->getIsPrimary());
    }

    public function testAddressJsonSerialize(): void {
        $address = new Address();
        $address->setId(1);
        $address->setMemberId(10);
        $address->setStrasse('Musterstrasse 1');
        $address->setPlz('12345');
        $address->setOrt('Musterstadt');

        $json = $address->jsonSerialize();

        $this->assertSame(1, $json['id']);
        $this->assertSame(10, $json['memberId']);
        $this->assertSame('Musterstrasse 1', $json['strasse']);
        $this->assertSame('12345', $json['plz']);
        $this->assertSame('Musterstadt', $json['ort']);
        $this->assertSame('Deutschland', $json['land']);
        $this->assertFalse($json['isPrimary']);
        $this->assertArrayHasKey('label', $json);
    }

    // ── Phone ───────────────────────────────────────────────────────

    public function testPhoneDefaultValues(): void {
        $phone = new Phone();
        $this->assertSame(0, $phone->getMemberId());
        $this->assertNull($phone->getLabel());
        $this->assertSame('', $phone->getNumberE164());
    }

    public function testPhoneGettersSetters(): void {
        $phone = new Phone();
        $phone->setId(1);
        $phone->setMemberId(10);
        $phone->setLabel('Mobil');
        $phone->setNumberE164('+491234567890');

        $this->assertSame(1, $phone->getId());
        $this->assertSame(10, $phone->getMemberId());
        $this->assertSame('Mobil', $phone->getLabel());
        $this->assertSame('+491234567890', $phone->getNumberE164());
    }

    public function testPhoneJsonSerialize(): void {
        $phone = new Phone();
        $phone->setId(1);
        $phone->setMemberId(10);
        $phone->setNumberE164('+491234567890');

        $json = $phone->jsonSerialize();

        $this->assertSame(1, $json['id']);
        $this->assertSame(10, $json['memberId']);
        $this->assertSame('+491234567890', $json['numberE164']);
        $this->assertArrayHasKey('label', $json);
    }

    // ── Email ───────────────────────────────────────────────────────

    public function testEmailDefaultValues(): void {
        $email = new Email();
        $this->assertSame(0, $email->getMemberId());
        $this->assertNull($email->getLabel());
        $this->assertSame('', $email->getEmail());
    }

    public function testEmailGettersSetters(): void {
        $email = new Email();
        $email->setId(1);
        $email->setMemberId(10);
        $email->setLabel('Privat');
        $email->setEmail('test@example.com');

        $this->assertSame(1, $email->getId());
        $this->assertSame(10, $email->getMemberId());
        $this->assertSame('Privat', $email->getLabel());
        $this->assertSame('test@example.com', $email->getEmail());
    }

    public function testEmailJsonSerialize(): void {
        $email = new Email();
        $email->setId(1);
        $email->setMemberId(10);
        $email->setEmail('test@example.com');

        $json = $email->jsonSerialize();

        $this->assertSame(1, $json['id']);
        $this->assertSame(10, $json['memberId']);
        $this->assertSame('test@example.com', $json['email']);
        $this->assertArrayHasKey('label', $json);
    }

    // ── FeeRecord ───────────────────────────────────────────────────

    public function testFeeRecordDefaultValues(): void {
        $record = new FeeRecord();
        $this->assertSame(0, $record->getMemberId());
        $this->assertSame(0, $record->getYear());
        $this->assertNull($record->getAmount());
        $this->assertNull($record->getRuleSnapshotJson());
        $this->assertFalse($record->getManuellAngepasst());
        $this->assertFalse($record->getPaid());
        $this->assertNull($record->getPaymentDate());
        $this->assertNull($record->getNotes());
        $this->assertSame('', $record->getCreatedAt());
        $this->assertSame('', $record->getUpdatedAt());
    }

    public function testFeeRecordGettersSetters(): void {
        $record = new FeeRecord();
        $record->setId(1);
        $record->setMemberId(10);
        $record->setYear(2026);
        $record->setAmount('120.00');
        $record->setRuleSnapshotJson('{"baseRate":"120.00"}');
        $record->setManuellAngepasst(true);
        $record->setPaid(true);
        $record->setPaymentDate('2026-03-15');
        $record->setNotes('Paid via SEPA');
        $record->setCreatedAt('2026-01-01 00:00:00');
        $record->setUpdatedAt('2026-03-15 10:00:00');

        $this->assertSame(1, $record->getId());
        $this->assertSame(10, $record->getMemberId());
        $this->assertSame(2026, $record->getYear());
        $this->assertSame('120.00', $record->getAmount());
        $this->assertSame('{"baseRate":"120.00"}', $record->getRuleSnapshotJson());
        $this->assertTrue($record->getManuellAngepasst());
        $this->assertTrue($record->getPaid());
        $this->assertSame('2026-03-15', $record->getPaymentDate());
        $this->assertSame('Paid via SEPA', $record->getNotes());
        $this->assertSame('2026-01-01 00:00:00', $record->getCreatedAt());
        $this->assertSame('2026-03-15 10:00:00', $record->getUpdatedAt());
    }

    public function testFeeRecordJsonSerialize(): void {
        $record = new FeeRecord();
        $record->setId(1);
        $record->setMemberId(10);
        $record->setYear(2026);
        $record->setAmount('120.00');
        $record->setCreatedAt('2026-01-01');
        $record->setUpdatedAt('2026-01-01');

        $json = $record->jsonSerialize();

        $this->assertSame(1, $json['id']);
        $this->assertSame(10, $json['memberId']);
        $this->assertSame(2026, $json['year']);
        $this->assertSame('120.00', $json['amount']);
        $this->assertFalse($json['manuellAngepasst']);
        $this->assertFalse($json['paid']);
        $this->assertArrayHasKey('ruleSnapshotJson', $json);
        $this->assertArrayHasKey('paymentDate', $json);
        $this->assertArrayHasKey('notes', $json);
    }

    // ── FeeRule ─────────────────────────────────────────────────────

    public function testFeeRuleDefaultValues(): void {
        $rule = new FeeRule();
        $this->assertSame(0, $rule->getYearFrom());
        $this->assertSame('0.00', $rule->getBaseRate());
        $this->assertSame('{}', $rule->getFamilyRulesJson());
        $this->assertSame('freeze_rate_at_exit', $rule->getInactiveRule());
        $this->assertSame('', $rule->getCreatedAt());
        $this->assertSame('', $rule->getCreatedBy());
    }

    public function testFeeRuleGettersSetters(): void {
        $rule = new FeeRule();
        $rule->setId(1);
        $rule->setYearFrom(2026);
        $rule->setBaseRate('120.00');
        $rule->setFamilyRulesJson('{"1":100,"2":75,"3+":50}');
        $rule->setInactiveRule('zero_fee');
        $rule->setCreatedAt('2026-01-01 00:00:00');
        $rule->setCreatedBy('admin');

        $this->assertSame(1, $rule->getId());
        $this->assertSame(2026, $rule->getYearFrom());
        $this->assertSame('120.00', $rule->getBaseRate());
        $this->assertSame('{"1":100,"2":75,"3+":50}', $rule->getFamilyRulesJson());
        $this->assertSame('zero_fee', $rule->getInactiveRule());
        $this->assertSame('2026-01-01 00:00:00', $rule->getCreatedAt());
        $this->assertSame('admin', $rule->getCreatedBy());
    }

    public function testFeeRuleGetFamilyRules(): void {
        $rule = new FeeRule();
        $rule->setFamilyRulesJson('{"1":100,"2":75,"3+":50}');

        $familyRules = $rule->getFamilyRules();

        $this->assertSame(100, $familyRules['1']);
        $this->assertSame(75, $familyRules['2']);
        $this->assertSame(50, $familyRules['3+']);
    }

    public function testFeeRuleGetFamilyRulesWithEmptyJson(): void {
        $rule = new FeeRule();
        $this->assertSame([], $rule->getFamilyRules());
    }

    public function testFeeRuleGetFamilyRulesWithInvalidJson(): void {
        $rule = new FeeRule();
        $rule->setFamilyRulesJson('not-json');
        $this->assertSame([], $rule->getFamilyRules());
    }

    public function testFeeRuleJsonSerialize(): void {
        $rule = new FeeRule();
        $rule->setId(1);
        $rule->setYearFrom(2026);
        $rule->setBaseRate('120.00');
        $rule->setFamilyRulesJson('{"1":100}');
        $rule->setCreatedAt('2026-01-01');
        $rule->setCreatedBy('admin');

        $json = $rule->jsonSerialize();

        $this->assertSame(1, $json['id']);
        $this->assertSame(2026, $json['yearFrom']);
        $this->assertSame('120.00', $json['baseRate']);
        $this->assertSame(['1' => 100], $json['familyRules']);
        $this->assertSame('{"1":100}', $json['familyRulesJson']);
        $this->assertSame('freeze_rate_at_exit', $json['inactiveRule']);
    }

    // ── Injury ──────────────────────────────────────────────────────

    public function testInjuryDefaultValues(): void {
        $injury = new Injury();
        $this->assertSame('', $injury->getDatum());
        $this->assertSame(0, $injury->getMemberId());
        $this->assertNull($injury->getLagerId());
        $this->assertNull($injury->getActivityName());
        $this->assertSame('', $injury->getBeschreibung());
        $this->assertSame('', $injury->getCreatedBy());
        $this->assertSame('', $injury->getCreatedAt());
    }

    public function testInjuryGettersSetters(): void {
        $injury = new Injury();
        $injury->setId(1);
        $injury->setDatum('2026-04-01');
        $injury->setMemberId(10);
        $injury->setLagerId(5);
        $injury->setActivityName('Wanderung');
        $injury->setBeschreibung('Verstauchter Knoechel');
        $injury->setCreatedBy('leiter1');
        $injury->setCreatedAt('2026-04-01 15:30:00');

        $this->assertSame(1, $injury->getId());
        $this->assertSame('2026-04-01', $injury->getDatum());
        $this->assertSame(10, $injury->getMemberId());
        $this->assertSame(5, $injury->getLagerId());
        $this->assertSame('Wanderung', $injury->getActivityName());
        $this->assertSame('Verstauchter Knoechel', $injury->getBeschreibung());
        $this->assertSame('leiter1', $injury->getCreatedBy());
        $this->assertSame('2026-04-01 15:30:00', $injury->getCreatedAt());
    }

    public function testInjuryJsonSerialize(): void {
        $injury = new Injury();
        $injury->setId(1);
        $injury->setDatum('2026-04-01');
        $injury->setMemberId(10);
        $injury->setBeschreibung('Test');
        $injury->setCreatedBy('admin');
        $injury->setCreatedAt('2026-04-01');

        $json = $injury->jsonSerialize();

        $this->assertSame(1, $json['id']);
        $this->assertSame('2026-04-01', $json['datum']);
        $this->assertSame(10, $json['memberId']);
        $this->assertNull($json['lagerId']);
        $this->assertNull($json['activityName']);
        $this->assertSame('Test', $json['beschreibung']);
    }

    // ── Lager ───────────────────────────────────────────────────────

    public function testLagerDefaultValues(): void {
        $lager = new Lager();
        $this->assertSame('', $lager->getName());
        $this->assertSame('', $lager->getStartdatum());
        $this->assertSame('', $lager->getEnddatum());
        $this->assertNull($lager->getOrt());
        $this->assertNull($lager->getBeschreibung());
        $this->assertNull($lager->getFilesFolderPath());
        $this->assertSame('', $lager->getCreatedAt());
        $this->assertSame('', $lager->getUpdatedAt());
    }

    public function testLagerGettersSetters(): void {
        $lager = new Lager();
        $lager->setId(1);
        $lager->setName('Sommerlager 2026');
        $lager->setStartdatum('2026-07-15');
        $lager->setEnddatum('2026-07-25');
        $lager->setOrt('Schwarzwald');
        $lager->setBeschreibung('Jaehrliches Sommerlager');
        $lager->setFilesFolderPath('/files/lager/2026');
        $lager->setCreatedAt('2026-01-01 00:00:00');
        $lager->setUpdatedAt('2026-06-01 12:00:00');

        $this->assertSame(1, $lager->getId());
        $this->assertSame('Sommerlager 2026', $lager->getName());
        $this->assertSame('2026-07-15', $lager->getStartdatum());
        $this->assertSame('2026-07-25', $lager->getEnddatum());
        $this->assertSame('Schwarzwald', $lager->getOrt());
        $this->assertSame('Jaehrliches Sommerlager', $lager->getBeschreibung());
        $this->assertSame('/files/lager/2026', $lager->getFilesFolderPath());
        $this->assertSame('2026-01-01 00:00:00', $lager->getCreatedAt());
        $this->assertSame('2026-06-01 12:00:00', $lager->getUpdatedAt());
    }

    public function testLagerJsonSerialize(): void {
        $lager = new Lager();
        $lager->setId(1);
        $lager->setName('Sommerlager');
        $lager->setStartdatum('2026-07-15');
        $lager->setEnddatum('2026-07-25');
        $lager->setCreatedAt('2026-01-01');
        $lager->setUpdatedAt('2026-01-01');

        $json = $lager->jsonSerialize();

        $this->assertSame(1, $json['id']);
        $this->assertSame('Sommerlager', $json['name']);
        $this->assertSame('2026-07-15', $json['startdatum']);
        $this->assertSame('2026-07-25', $json['enddatum']);
        $this->assertNull($json['ort']);
        $this->assertNull($json['beschreibung']);
        $this->assertNull($json['filesFolderPath']);
    }

    // ── LagerTeilnehmer ─────────────────────────────────────────────

    public function testLagerTeilnehmerDefaultValues(): void {
        $lt = new LagerTeilnehmer();
        $this->assertSame(0, $lt->getLagerId());
        $this->assertSame(0, $lt->getMemberId());
        $this->assertSame('Teilnehmer', $lt->getRolle());
    }

    public function testLagerTeilnehmerGettersSetters(): void {
        $lt = new LagerTeilnehmer();
        $lt->setLagerId(5);
        $lt->setMemberId(10);
        $lt->setRolle('Leiter');

        $this->assertSame(5, $lt->getLagerId());
        $this->assertSame(10, $lt->getMemberId());
        $this->assertSame('Leiter', $lt->getRolle());
    }

    public function testLagerTeilnehmerJsonSerialize(): void {
        $lt = new LagerTeilnehmer();
        $lt->setLagerId(5);
        $lt->setMemberId(10);
        $lt->setRolle('Teilnehmer');

        $json = $lt->jsonSerialize();

        $this->assertSame(5, $json['lagerId']);
        $this->assertSame(10, $json['memberId']);
        $this->assertSame('Teilnehmer', $json['rolle']);
    }

    // ── AuditLog ────────────────────────────────────────────────────

    public function testAuditLogDefaultValues(): void {
        $log = new AuditLog();
        $this->assertSame('', $log->getZeitpunkt());
        $this->assertSame('', $log->getNcUserId());
        $this->assertSame('', $log->getAktion());
        $this->assertSame('', $log->getEntitaet());
        $this->assertSame(0, $log->getEntitaetId());
        $this->assertNull($log->getFeld());
        $this->assertNull($log->getAlterWert());
        $this->assertNull($log->getNeuerWert());
    }

    public function testAuditLogGettersSetters(): void {
        $log = new AuditLog();
        $log->setId(1);
        $log->setZeitpunkt('2026-04-09 10:00:00');
        $log->setNcUserId('admin');
        $log->setAktion('update');
        $log->setEntitaet('member');
        $log->setEntitaetId(42);
        $log->setFeld('vorname');
        $log->setAlterWert('Max');
        $log->setNeuerWert('Maximilian');

        $this->assertSame(1, $log->getId());
        $this->assertSame('2026-04-09 10:00:00', $log->getZeitpunkt());
        $this->assertSame('admin', $log->getNcUserId());
        $this->assertSame('update', $log->getAktion());
        $this->assertSame('member', $log->getEntitaet());
        $this->assertSame(42, $log->getEntitaetId());
        $this->assertSame('vorname', $log->getFeld());
        $this->assertSame('Max', $log->getAlterWert());
        $this->assertSame('Maximilian', $log->getNeuerWert());
    }

    public function testAuditLogJsonSerialize(): void {
        $log = new AuditLog();
        $log->setId(1);
        $log->setZeitpunkt('2026-04-09 10:00:00');
        $log->setNcUserId('admin');
        $log->setAktion('create');
        $log->setEntitaet('member');
        $log->setEntitaetId(42);

        $json = $log->jsonSerialize();

        $this->assertSame(1, $json['id']);
        $this->assertSame('2026-04-09 10:00:00', $json['zeitpunkt']);
        $this->assertSame('admin', $json['ncUserId']);
        $this->assertSame('create', $json['aktion']);
        $this->assertSame('member', $json['entitaet']);
        $this->assertSame(42, $json['entitaetId']);
        $this->assertNull($json['feld']);
        $this->assertNull($json['alterWert']);
        $this->assertNull($json['neuerWert']);
    }

    // ── Permission ──────────────────────────────────────────────────

    public function testPermissionDefaultValues(): void {
        $perm = new Permission();
        $this->assertSame('', $perm->getNcUserId());
        $this->assertSame('none', $perm->getLevel());
        $this->assertNull($perm->getAllowedStufenJson());
        $this->assertFalse($perm->getCanSeeBanking());
    }

    public function testPermissionGettersSetters(): void {
        $perm = new Permission();
        $perm->setId(1);
        $perm->setNcUserId('leiter1');
        $perm->setLevel('write');
        $perm->setAllowedStufenJson('[1,2,3]');
        $perm->setCanSeeBanking(true);

        $this->assertSame(1, $perm->getId());
        $this->assertSame('leiter1', $perm->getNcUserId());
        $this->assertSame('write', $perm->getLevel());
        $this->assertSame('[1,2,3]', $perm->getAllowedStufenJson());
        $this->assertTrue($perm->getCanSeeBanking());
    }

    public function testPermissionGetAllowedStufen(): void {
        $perm = new Permission();
        $perm->setAllowedStufenJson('[1,2,3]');

        $stufen = $perm->getAllowedStufen();
        $this->assertSame([1, 2, 3], $stufen);
    }

    public function testPermissionGetAllowedStufenNullJson(): void {
        $perm = new Permission();
        $this->assertSame([], $perm->getAllowedStufen());
    }

    public function testPermissionGetAllowedStufenInvalidJson(): void {
        $perm = new Permission();
        $perm->setAllowedStufenJson('invalid');
        $this->assertSame([], $perm->getAllowedStufen());
    }

    public function testPermissionJsonSerialize(): void {
        $perm = new Permission();
        $perm->setId(1);
        $perm->setNcUserId('leiter1');
        $perm->setLevel('admin');
        $perm->setAllowedStufenJson('[1,2]');
        $perm->setCanSeeBanking(true);

        $json = $perm->jsonSerialize();

        $this->assertSame(1, $json['id']);
        $this->assertSame('leiter1', $json['ncUserId']);
        $this->assertSame('admin', $json['level']);
        $this->assertSame([1, 2], $json['allowedStufen']);
        $this->assertTrue($json['canSeeBanking']);
    }

    // ── SavedQuery ──────────────────────────────────────────────────

    public function testSavedQueryDefaultValues(): void {
        $query = new SavedQuery();
        $this->assertSame('', $query->getName());
        $this->assertSame('', $query->getQueryJson());
        $this->assertNull($query->getSortJson());
        $this->assertSame('', $query->getCreatedBy());
        $this->assertSame('', $query->getCreatedAt());
    }

    public function testSavedQueryGettersSetters(): void {
        $query = new SavedQuery();
        $query->setId(1);
        $query->setName('Active Members');
        $query->setQueryJson('{"status":"aktiv"}');
        $query->setSortJson('{"field":"nachname","dir":"ASC"}');
        $query->setCreatedBy('admin');
        $query->setCreatedAt('2026-01-01 00:00:00');

        $this->assertSame(1, $query->getId());
        $this->assertSame('Active Members', $query->getName());
        $this->assertSame('{"status":"aktiv"}', $query->getQueryJson());
        $this->assertSame('{"field":"nachname","dir":"ASC"}', $query->getSortJson());
        $this->assertSame('admin', $query->getCreatedBy());
        $this->assertSame('2026-01-01 00:00:00', $query->getCreatedAt());
    }

    public function testSavedQueryJsonSerialize(): void {
        $query = new SavedQuery();
        $query->setId(1);
        $query->setName('Active Members');
        $query->setQueryJson('{"status":"aktiv"}');
        $query->setSortJson('{"field":"nachname","dir":"ASC"}');
        $query->setCreatedBy('admin');
        $query->setCreatedAt('2026-01-01');

        $json = $query->jsonSerialize();

        $this->assertSame(1, $json['id']);
        $this->assertSame('Active Members', $json['name']);
        $this->assertSame(['status' => 'aktiv'], $json['queryJson']);
        $this->assertSame(['field' => 'nachname', 'dir' => 'ASC'], $json['sortJson']);
        $this->assertSame('admin', $json['createdBy']);
    }

    public function testSavedQueryJsonSerializeWithNullSort(): void {
        $query = new SavedQuery();
        $query->setId(1);
        $query->setName('Test');
        $query->setQueryJson('{"status":"aktiv"}');
        $query->setCreatedBy('admin');
        $query->setCreatedAt('2026-01-01');

        $json = $query->jsonSerialize();

        $this->assertNull($json['sortJson']);
    }

    // ── Stufe ───────────────────────────────────────────────────────

    public function testStufeDefaultValues(): void {
        $stufe = new Stufe();
        $this->assertSame('', $stufe->getName());
        $this->assertSame(0, $stufe->getSortOrder());
        $this->assertNull($stufe->getAgeRangeMin());
        $this->assertNull($stufe->getAgeRangeMax());
        $this->assertNull($stufe->getColor());
    }

    public function testStufeGettersSetters(): void {
        $stufe = new Stufe();
        $stufe->setId(1);
        $stufe->setName('Woelflinge');
        $stufe->setSortOrder(1);
        $stufe->setAgeRangeMin(6);
        $stufe->setAgeRangeMax(10);
        $stufe->setColor('#FF9900');

        $this->assertSame(1, $stufe->getId());
        $this->assertSame('Woelflinge', $stufe->getName());
        $this->assertSame(1, $stufe->getSortOrder());
        $this->assertSame(6, $stufe->getAgeRangeMin());
        $this->assertSame(10, $stufe->getAgeRangeMax());
        $this->assertSame('#FF9900', $stufe->getColor());
    }

    public function testStufeJsonSerialize(): void {
        $stufe = new Stufe();
        $stufe->setId(1);
        $stufe->setName('Woelflinge');
        $stufe->setSortOrder(1);
        $stufe->setAgeRangeMin(6);
        $stufe->setAgeRangeMax(10);
        $stufe->setColor('#FF9900');

        $json = $stufe->jsonSerialize();

        $this->assertSame(1, $json['id']);
        $this->assertSame('Woelflinge', $json['name']);
        $this->assertSame(1, $json['sortOrder']);
        $this->assertSame(6, $json['ageRangeMin']);
        $this->assertSame(10, $json['ageRangeMax']);
        $this->assertSame('#FF9900', $json['color']);
    }

    // ── StufeHistory ────────────────────────────────────────────────

    public function testStufeHistoryDefaultValues(): void {
        $sh = new StufeHistory();
        $this->assertSame(0, $sh->getMemberId());
        $this->assertSame(0, $sh->getStufeId());
        $this->assertSame('', $sh->getChangedAt());
        $this->assertSame('', $sh->getChangedBy());
    }

    public function testStufeHistoryGettersSetters(): void {
        $sh = new StufeHistory();
        $sh->setId(1);
        $sh->setMemberId(10);
        $sh->setStufeId(3);
        $sh->setChangedAt('2026-04-01 12:00:00');
        $sh->setChangedBy('admin');

        $this->assertSame(1, $sh->getId());
        $this->assertSame(10, $sh->getMemberId());
        $this->assertSame(3, $sh->getStufeId());
        $this->assertSame('2026-04-01 12:00:00', $sh->getChangedAt());
        $this->assertSame('admin', $sh->getChangedBy());
    }

    public function testStufeHistoryJsonSerialize(): void {
        $sh = new StufeHistory();
        $sh->setId(1);
        $sh->setMemberId(10);
        $sh->setStufeId(3);
        $sh->setChangedAt('2026-04-01 12:00:00');
        $sh->setChangedBy('admin');

        $json = $sh->jsonSerialize();

        $this->assertSame(1, $json['id']);
        $this->assertSame(10, $json['memberId']);
        $this->assertSame(3, $json['stufeId']);
        $this->assertSame('2026-04-01 12:00:00', $json['changedAt']);
        $this->assertSame('admin', $json['changedBy']);
    }
}
