<?php

declare(strict_types=1);

namespace OCA\Mitgliederverwaltung\Controller;

use OCA\Mitgliederverwaltung\Service\CsvExportService;
use OCA\Mitgliederverwaltung\Service\EncryptedExportService;
use OCA\Mitgliederverwaltung\Service\EntityExportService;
use OCA\Mitgliederverwaltung\Service\ValidationException;
use OCP\AppFramework\ApiController;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\DataDownloadResponse;
use OCP\AppFramework\Http\JSONResponse;
use OCP\IRequest;
use Psr\Log\LoggerInterface;

/**
 * REST API controller for data export (CSV downloads, encrypted ZIPs).
 *
 * Plain CSV endpoints use GET (no sensitive parameters).
 * Encrypted endpoints use POST (password in request body, not URL).
 *
 * Part of Issues #47, #48.
 */
class ExportController extends ApiController {

    private CsvExportService $csvService;
    private EncryptedExportService $encryptedService;
    private EntityExportService $entityExportService;
    private LoggerInterface $logger;

    public function __construct(
        string $appName,
        IRequest $request,
        CsvExportService $csvService,
        EncryptedExportService $encryptedService,
        EntityExportService $entityExportService,
        LoggerInterface $logger
    ) {
        parent::__construct($appName, $request);
        $this->csvService = $csvService;
        $this->encryptedService = $encryptedService;
        $this->entityExportService = $entityExportService;
        $this->logger = $logger;
    }

    // ── Plain CSV exports ───────────────────────────────────────────

    /**
     * Export member list as CSV.
     *
     * GET /api/v1/export/members?status=aktiv
     */
    #[NoCSRFRequired]
    public function members(): DataDownloadResponse|JSONResponse {
        try {
            $status = $this->request->getParam('status');

            $result = $this->csvService->exportMemberList($status);

            return new DataDownloadResponse(
                $result['content'],
                $result['filename'],
                'text/csv; charset=utf-8'
            );
        } catch (\Exception $e) {
            $this->logger->error('Failed to export members CSV', [
                'exception' => $e,
                'app' => 'mitgliederverwaltung',
            ]);
            return new JSONResponse(
                ['error' => 'Export fehlgeschlagen'],
                Http::STATUS_INTERNAL_SERVER_ERROR
            );
        }
    }

    /**
     * Export fee records as CSV.
     *
     * GET /api/v1/export/fees?year=2026
     */
    #[NoCSRFRequired]
    public function fees(): DataDownloadResponse|JSONResponse {
        try {
            $year = $this->request->getParam('year');

            if ($year === null) {
                return new JSONResponse(
                    ['error' => 'Parameter year ist erforderlich'],
                    Http::STATUS_BAD_REQUEST
                );
            }

            $result = $this->csvService->exportFeeRecords((int)$year);

            return new DataDownloadResponse(
                $result['content'],
                $result['filename'],
                'text/csv; charset=utf-8'
            );
        } catch (\Exception $e) {
            $this->logger->error('Failed to export fees CSV', [
                'exception' => $e,
                'app' => 'mitgliederverwaltung',
            ]);
            return new JSONResponse(
                ['error' => 'Export fehlgeschlagen'],
                Http::STATUS_INTERNAL_SERVER_ERROR
            );
        }
    }

    /**
     * Export birthday list as CSV.
     *
     * GET /api/v1/export/birthdays?month=4
     */
    #[NoCSRFRequired]
    public function birthdays(): DataDownloadResponse|JSONResponse {
        try {
            $month = $this->request->getParam('month');

            if ($month === null) {
                // Default to current month
                $month = (int)(new \DateTime())->format('m');
            }

            $result = $this->csvService->exportBirthdayList((int)$month);

            return new DataDownloadResponse(
                $result['content'],
                $result['filename'],
                'text/csv; charset=utf-8'
            );
        } catch (\Exception $e) {
            $this->logger->error('Failed to export birthdays CSV', [
                'exception' => $e,
                'app' => 'mitgliederverwaltung',
            ]);
            return new JSONResponse(
                ['error' => 'Export fehlgeschlagen'],
                Http::STATUS_INTERNAL_SERVER_ERROR
            );
        }
    }

    // ── Encrypted exports ───────────────────────────────────────────

    /**
     * Export member list as encrypted ZIP.
     *
     * POST /api/v1/export/members/encrypted
     * Body: { "password": "...", "status": "aktiv" }
     */
    public function membersEncrypted(): DataDownloadResponse|JSONResponse {
        try {
            $password = $this->request->getParam('password');
            if ($password === null || $password === '') {
                return new JSONResponse(
                    ['error' => 'Passwort ist erforderlich'],
                    Http::STATUS_BAD_REQUEST
                );
            }

            $status = $this->request->getParam('status');
            $csvResult = $this->csvService->exportMemberList($status);

            $zipResult = $this->encryptedService->createEncryptedExport(
                $csvResult['content'],
                $csvResult['filename'],
                $password,
                'Mitgliederliste'
            );

            return new DataDownloadResponse(
                $zipResult['content'],
                $zipResult['filename'],
                'application/zip'
            );
        } catch (ValidationException $e) {
            return new JSONResponse(
                ['error' => $e->getMessage()],
                Http::STATUS_UNPROCESSABLE_ENTITY
            );
        } catch (\Exception $e) {
            $this->logger->error('Failed to create encrypted member export', [
                'exception' => $e,
                'app' => 'mitgliederverwaltung',
            ]);
            return new JSONResponse(
                ['error' => 'Verschluesselter Export fehlgeschlagen'],
                Http::STATUS_INTERNAL_SERVER_ERROR
            );
        }
    }

    /**
     * Export fee records as encrypted ZIP.
     *
     * POST /api/v1/export/fees/encrypted
     * Body: { "password": "...", "year": 2026 }
     */
    public function feesEncrypted(): DataDownloadResponse|JSONResponse {
        try {
            $password = $this->request->getParam('password');
            if ($password === null || $password === '') {
                return new JSONResponse(
                    ['error' => 'Passwort ist erforderlich'],
                    Http::STATUS_BAD_REQUEST
                );
            }

            $year = $this->request->getParam('year');
            if ($year === null) {
                return new JSONResponse(
                    ['error' => 'Parameter year ist erforderlich'],
                    Http::STATUS_BAD_REQUEST
                );
            }

            $csvResult = $this->csvService->exportFeeRecords((int)$year);

            $zipResult = $this->encryptedService->createEncryptedExport(
                $csvResult['content'],
                $csvResult['filename'],
                $password,
                'Beitragsliste'
            );

            return new DataDownloadResponse(
                $zipResult['content'],
                $zipResult['filename'],
                'application/zip'
            );
        } catch (ValidationException $e) {
            return new JSONResponse(
                ['error' => $e->getMessage()],
                Http::STATUS_UNPROCESSABLE_ENTITY
            );
        } catch (\Exception $e) {
            $this->logger->error('Failed to create encrypted fees export', [
                'exception' => $e,
                'app' => 'mitgliederverwaltung',
            ]);
            return new JSONResponse(
                ['error' => 'Verschluesselter Export fehlgeschlagen'],
                Http::STATUS_INTERNAL_SERVER_ERROR
            );
        }
    }

    /**
     * Export birthday list as encrypted ZIP.
     *
     * POST /api/v1/export/birthdays/encrypted
     * Body: { "password": "...", "month": 4 }
     */
    public function birthdaysEncrypted(): DataDownloadResponse|JSONResponse {
        try {
            $password = $this->request->getParam('password');
            if ($password === null || $password === '') {
                return new JSONResponse(
                    ['error' => 'Passwort ist erforderlich'],
                    Http::STATUS_BAD_REQUEST
                );
            }

            $month = $this->request->getParam('month');
            if ($month === null) {
                $month = (int)(new \DateTime())->format('m');
            }

            $csvResult = $this->csvService->exportBirthdayList((int)$month);

            $zipResult = $this->encryptedService->createEncryptedExport(
                $csvResult['content'],
                $csvResult['filename'],
                $password,
                'Geburtstagsliste'
            );

            return new DataDownloadResponse(
                $zipResult['content'],
                $zipResult['filename'],
                'application/zip'
            );
        } catch (ValidationException $e) {
            return new JSONResponse(
                ['error' => $e->getMessage()],
                Http::STATUS_UNPROCESSABLE_ENTITY
            );
        } catch (\Exception $e) {
            $this->logger->error('Failed to create encrypted birthdays export', [
                'exception' => $e,
                'app' => 'mitgliederverwaltung',
            ]);
            return new JSONResponse(
                ['error' => 'Verschluesselter Export fehlgeschlagen'],
                Http::STATUS_INTERNAL_SERVER_ERROR
            );
        }
    }

    // ── Full bundle export (Issue #149) ────────────────────────────

    /**
     * Export all entity data as a ZIP bundle (without sensitive data).
     *
     * GET /api/v1/export/bundle
     */
    #[NoCSRFRequired]
    public function bundle(): DataDownloadResponse|JSONResponse {
        try {
            $result = $this->entityExportService->exportFullBundle(false);

            $content = file_get_contents($result['path']);
            unlink($result['path']);

            if ($content === false) {
                return new JSONResponse(
                    ['error' => 'ZIP konnte nicht gelesen werden'],
                    Http::STATUS_INTERNAL_SERVER_ERROR
                );
            }

            return new DataDownloadResponse(
                $content,
                $result['filename'],
                'application/zip'
            );
        } catch (\Exception $e) {
            $this->logger->error('Failed to create bundle export', [
                'exception' => $e,
                'app' => 'mitgliederverwaltung',
            ]);
            return new JSONResponse(
                ['error' => 'Vollstaendiger Export fehlgeschlagen'],
                Http::STATUS_INTERNAL_SERVER_ERROR
            );
        }
    }

    /**
     * Export all entity data as a ZIP bundle with sensitive data decrypted.
     *
     * POST /api/v1/export/bundle/sensitive
     * Body: { "confirm": true }
     *
     * Requires explicit confirmation because sensitive data is decrypted.
     */
    public function bundleSensitive(): DataDownloadResponse|JSONResponse {
        try {
            $confirm = $this->request->getParam('confirm');
            if ($confirm !== true && $confirm !== 'true' && $confirm !== '1' && $confirm !== 1) {
                return new JSONResponse(
                    ['error' => 'Bestaetigung erforderlich (confirm: true)'],
                    Http::STATUS_BAD_REQUEST
                );
            }

            $result = $this->entityExportService->exportFullBundle(true);

            $content = file_get_contents($result['path']);
            unlink($result['path']);

            if ($content === false) {
                return new JSONResponse(
                    ['error' => 'ZIP konnte nicht gelesen werden'],
                    Http::STATUS_INTERNAL_SERVER_ERROR
                );
            }

            return new DataDownloadResponse(
                $content,
                $result['filename'],
                'application/zip'
            );
        } catch (\Exception $e) {
            $this->logger->error('Failed to create sensitive bundle export', [
                'exception' => $e,
                'app' => 'mitgliederverwaltung',
            ]);
            return new JSONResponse(
                ['error' => 'Sensibler Export fehlgeschlagen'],
                Http::STATUS_INTERNAL_SERVER_ERROR
            );
        }
    }

    // ── Per-entity exports (Issue #148) ────────────────────────────

    /**
     * List all exportable entity types.
     *
     * GET /api/v1/export/entity-types
     */
    #[NoCSRFRequired]
    public function entityTypes(): JSONResponse {
        return new JSONResponse($this->entityExportService->getEntityTypes());
    }

    /**
     * Export a single entity type as CSV.
     *
     * GET /api/v1/export/entity/{type}
     */
    #[NoCSRFRequired]
    public function entity(string $type): DataDownloadResponse|JSONResponse {
        try {
            $result = $this->entityExportService->exportEntity($type);

            return new DataDownloadResponse(
                $result['content'],
                $result['filename'],
                'text/csv; charset=utf-8'
            );
        } catch (\InvalidArgumentException $e) {
            return new JSONResponse(
                ['error' => $e->getMessage()],
                Http::STATUS_BAD_REQUEST
            );
        } catch (\Exception $e) {
            $this->logger->error('Failed to export entity CSV', [
                'type' => $type,
                'exception' => $e,
                'app' => 'mitgliederverwaltung',
            ]);
            return new JSONResponse(
                ['error' => 'Export fehlgeschlagen'],
                Http::STATUS_INTERNAL_SERVER_ERROR
            );
        }
    }

    /**
     * Export banking data as encrypted ZIP.
     *
     * Requires banking visibility permission. This is the most sensitive
     * export — it contains decrypted IBAN and Kontoinhaber data.
     *
     * POST /api/v1/export/banking/encrypted
     * Body: { "password": "..." }
     */
    public function bankingEncrypted(): DataDownloadResponse|JSONResponse {
        try {
            // Permission check: banking visibility required
            $this->encryptedService->assertBankingExportPermission();

            $password = $this->request->getParam('password');
            if ($password === null || $password === '') {
                return new JSONResponse(
                    ['error' => 'Passwort ist erforderlich'],
                    Http::STATUS_BAD_REQUEST
                );
            }

            $csvResult = $this->csvService->exportBankingList();

            $zipResult = $this->encryptedService->createEncryptedExport(
                $csvResult['content'],
                $csvResult['filename'],
                $password,
                'Bankverbindungen'
            );

            return new DataDownloadResponse(
                $zipResult['content'],
                $zipResult['filename'],
                'application/zip'
            );
        } catch (ValidationException $e) {
            return new JSONResponse(
                ['error' => $e->getMessage()],
                Http::STATUS_FORBIDDEN
            );
        } catch (\Exception $e) {
            $this->logger->error('Failed to create encrypted banking export', [
                'exception' => $e,
                'app' => 'mitgliederverwaltung',
            ]);
            return new JSONResponse(
                ['error' => 'Verschluesselter Export fehlgeschlagen'],
                Http::STATUS_INTERNAL_SERVER_ERROR
            );
        }
    }
}
