<?php
declare(strict_types=1);

namespace Itdatex\Ausgangsrechnung;

if ( ! defined( 'ABSPATH' ) ) { exit; }

use Itdatex\EInvoiceCore\InvoiceRepository;
use Itdatex\EInvoiceCore\Storage;

/**
 * Sichere Datei-Auslieferung der erzeugten Rechnungs-XML.
 *
 * Spiegelt das Pattern aus rechnungseingang/DownloadHandler — eigenes
 * ACTION/NONCE, damit Eingangs- und Ausgangs-Downloads getrennt gehookt
 * werden koennen, aber dieselbe Storage- und Repository-Schicht.
 */
final class DownloadHandler
{
    public const ACTION = 'ausrg_download';
    public const NONCE  = 'ausrg_download_nonce';

    public function register(): void
    {
        add_action( 'admin_post_' . self::ACTION, [ $this, 'handle' ] );
    }

    public function handle(): void
    {
        if ( ! current_user_can( Plugin::CAPABILITY ) ) {
            wp_die( esc_html__( 'Keine Berechtigung.', 'itdatex-e-invoice-output' ), '', [ 'response' => 403 ] );
        }

        $fileId = isset( $_GET['file_id'] ) ? (int) $_GET['file_id'] : 0;
        if ( $fileId <= 0 ) {
            wp_die( 'Ungueltige Anfrage.', '', [ 'response' => 400 ] );
        }
        check_admin_referer( self::ACTION . '_' . $fileId, self::NONCE );

        $repo = new InvoiceRepository( 'outgoing' );
        $file = $repo->findFile( $fileId );
        if ( ! $file ) {
            wp_die( 'Datei nicht gefunden.', '', [ 'response' => 404 ] );
        }

        // Sicherheit: nur Dateien, die zu einer outgoing-Rechnung gehoeren
        $invoice = $repo->findInvoiceByFileId( $fileId );
        if ( ! $invoice || (string) $invoice->direction !== 'outgoing' ) {
            wp_die( 'Datei nicht zur Ausgangsrechnung gehoerig.', '', [ 'response' => 403 ] );
        }

        $storage  = new Storage( (string) get_option( 'reing_upload_dir', '' ) );
        $fullPath = $storage->fullPath( (string) $file->stored_name );
        if ( ! is_file( $fullPath ) || ! is_readable( $fullPath ) ) {
            wp_die( 'Datei nicht lesbar.', '', [ 'response' => 500 ] );
        }

        $repo->appendAudit(
            null,
            wp_get_current_user()->user_login ?: 'system',
            'downloaded',
            "file_id={$fileId}"
        );

        nocache_headers();
        header( 'Content-Type: ' . ( $file->mime ?: 'application/xml' ) );
        header( 'Content-Disposition: attachment; filename="' . self::safeFilename( (string) $file->original_name ) . '"' );
        header( 'Content-Length: ' . (int) $file->size_bytes );
        header( 'X-Content-Type-Options: nosniff' );

        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_readfile -- streaming download of a controlled, capability-and-nonce-checked file; loading into memory via WP_Filesystem would break for multi-MB PDFs.
        readfile( $fullPath );
        exit;
    }

    private static function safeFilename( string $name ): string
    {
        return str_replace( [ "\r", "\n", '"' ], '', $name );
    }
}
