<?php

declare(strict_types=1);

namespace OCA\Mitgliederverwaltung\Service;

use DateTime;
use OCA\Mitgliederverwaltung\Db\AddressMapper;
use OCA\Mitgliederverwaltung\Db\EmailMapper;
use OCA\Mitgliederverwaltung\Db\FeeRecordMapper;
use OCA\Mitgliederverwaltung\Db\FamilyMapper;
use OCA\Mitgliederverwaltung\Db\MemberMapper;
use OCA\Mitgliederverwaltung\Db\PhoneMapper;
use OCA\Mitgliederverwaltung\Db\StufeHistoryMapper;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\DB\Exception;
use Psr\Log\LoggerInterface;

/**
 * DSGVO compliance service for data export (Auskunftsrecht) and
 * irreversible hard-delete (Recht auf Loeschung).
 *
 * Part of Issue #62.
 */
class DsgvoService {

    private MemberMapper $memberMapper;
    private AddressMapper $addressMapper;
    private PhoneMapper $phoneMapper;
    private EmailMapper $emailMapper;
    private FamilyMapper $familyMapper;
    private FeeRecordMapper $feeRecordMapper;
    private StufeHistoryMapper $stufeHistoryMapper;
    private EncryptionService $encryptionService;
    private AuditService $auditService;
    private LoggerInterface $logger;

    public function __construct(
        MemberMapper $memberMapper,
        AddressMapper $addressMapper,
        PhoneMapper $phoneMapper,
        EmailMapper $emailMapper,
        FamilyMapper $familyMapper,
        FeeRecordMapper $feeRecordMapper,
        StufeHistoryMapper $stufeHistoryMapper,
        EncryptionService $encryptionService,
        AuditService $auditService,
        LoggerInterface $logger
    ) {
        $this->memberMapper = $memberMapper;
        $this->addressMapper = $addressMapper;
        $this->phoneMapper = $phoneMapper;
        $this->emailMapper = $emailMapper;
        $this->familyMapper = $familyMapper;
        $this->feeRecordMapper = $feeRecordMapper;
        $this->stufeHistoryMapper = $stufeHistoryMapper;
        $this->encryptionService = $encryptionService;
        $this->auditService = $auditService;
        $this->logger = $logger;
    }

    /**
     * Export all stored data for a member (Auskunftsrecht / Art. 15 DSGVO).
     *
     * Returns a structured array of all data stored about the member,
     * including decrypted sensitive fields. The caller is responsible
     * for encrypting the output (e.g., via EncryptedExportService).
     *
     * @param int $memberId
     * @return array Complete member data export
     * @throws DoesNotExistException
     * @throws Exception
     */
    public function exportMemberData(int $memberId): array {
        // Member may be soft-deleted; use includeDeleted=true via direct find
        $member = $this->memberMapper->findById($memberId);

        $addresses = [];
        try {
            $addresses = $this->addressMapper->findByMemberId($memberId);
        } catch (\Exception $e) {
            // May have been purged during soft-delete
        }

        $phones = [];
        try {
            $phones = $this->phoneMapper->findByMemberId($memberId);
        } catch (\Exception $e) {
            // May have been purged
        }

        $emails = [];
        try {
            $emails = $this->emailMapper->findByMemberId($memberId);
        } catch (\Exception $e) {
            // May have been purged
        }

        // Fee records
        $feeRecords = $this->feeRecordMapper->findByMemberId($memberId);

        // Stufe history
        $stufeHistory = $this->stufeHistoryMapper->findByMemberId($memberId);

        // Family info
        $familyData = null;
        if ($member->getFamilyId() !== null) {
            try {
                $family = $this->familyMapper->findById($member->getFamilyId());
                $familyData = [
                    'id' => $family->getId(),
                    'name' => $family->getName(),
                    'kontoinhaber' => $this->encryptionService->decrypt($family->getKontoinhaberEncrypted()),
                    'iban' => $this->encryptionService->decrypt($family->getIbanEncrypted()),
                    'bic' => $family->getBic(),
                    'kreditinstitut' => $family->getKreditinstitut(),
                ];
            } catch (DoesNotExistException $e) {
                // Family may have been deleted
            }
        }

        // Audit log entries for this member
        $auditLog = $this->auditService->getLog('member', $memberId);

        // Build export
        $export = [
            'exportDatum' => (new DateTime())->format('Y-m-d H:i:s'),
            'mitglied' => [
                'id' => $member->getId(),
                'vorname' => $member->getVorname(),
                'nachname' => $member->getNachname(),
                'geburtsdatum' => $member->getGeburtsdatum(),
                'geschlecht' => $member->getGeschlecht(),
                'rolle' => $member->getRolle(),
                'stufeId' => $member->getStufeId(),
                'eintritt' => $member->getEintritt(),
                'austritt' => $member->getAustritt(),
                'status' => $member->getStatus(),
                'allergien' => $this->encryptionService->decrypt($member->getAllergienEncrypted()),
                'notizen' => $member->getNotizen(),
                'zusatzNotizen' => $member->getZusatzNotizen(),
                'kvTyp' => $member->getKvTyp(),
                'kvName' => $member->getKvName(),
                'frozenFeeRate' => $member->getFrozenFeeRate(),
                'einwilligungDatum' => $member->getEinwilligungDatum(),
                'createdAt' => $member->getCreatedAt(),
                'updatedAt' => $member->getUpdatedAt(),
                'deletedAt' => $member->getDeletedAt(),
            ],
            'adressen' => array_map(fn($a) => $a->jsonSerialize(), $addresses),
            'telefonnummern' => array_map(fn($p) => $p->jsonSerialize(), $phones),
            'emailAdressen' => array_map(fn($e) => $e->jsonSerialize(), $emails),
            'familie' => $familyData,
            'beitragshistorie' => array_map(fn($f) => $f->jsonSerialize(), $feeRecords),
            'stufenhistorie' => array_map(fn($s) => $s->jsonSerialize(), $stufeHistory),
            'auditLog' => $auditLog['data'],
        ];

        // Audit log the export itself
        $this->auditService->logCreate(
            ['action' => 'dsgvo-export', 'memberId' => (string)$memberId],
            'dsgvo',
            $memberId
        );

        return $export;
    }

    /**
     * Irreversible hard-delete of all member data (Recht auf Loeschung / Art. 17 DSGVO).
     *
     * Removes ALL data including retained fields from soft-delete:
     * - Member record completely deleted from DB
     * - All related records (addresses, phones, emails, fee records, Stufe history)
     *
     * A final audit log entry is created BEFORE deletion to preserve
     * the record of who was deleted and by whom.
     *
     * @param int $memberId
     * @throws DoesNotExistException
     * @throws Exception
     */
    public function hardDeleteMember(int $memberId): void {
        $member = $this->memberMapper->findById($memberId);
        $memberName = $member->getVorname() . ' ' . $member->getNachname();

        // Create final audit log entry BEFORE deletion
        $this->auditService->logCreate(
            [
                'action' => 'dsgvo-loeschung',
                'name' => $memberName,
                'memberId' => (string)$memberId,
            ],
            'dsgvo',
            $memberId
        );

        // Delete all sub-entities
        $this->addressMapper->deleteByMemberId($memberId);
        $this->phoneMapper->deleteByMemberId($memberId);
        $this->emailMapper->deleteByMemberId($memberId);

        // Delete fee records
        $feeRecords = $this->feeRecordMapper->findByMemberId($memberId);
        foreach ($feeRecords as $record) {
            $this->feeRecordMapper->delete($record);
        }

        // Delete stufe history
        $stufeEntries = $this->stufeHistoryMapper->findByMemberId($memberId);
        foreach ($stufeEntries as $entry) {
            $this->stufeHistoryMapper->delete($entry);
        }

        // Finally delete the member record itself
        $this->memberMapper->delete($member);

        $this->logger->warning('DSGVO hard-delete executed', [
            'memberId' => $memberId,
            'memberName' => $memberName,
            'app' => 'mitgliederverwaltung',
        ]);
    }
}
