<?php
/**
 * Secure invoice and credit note download endpoint.
 *
 * Serves PDFs through a protected endpoint that verifies a per-document token.
 * Prevents direct URL access to the uploads directory.
 *
 * @package FacturX_For_WooCommerce
 */

defined( 'ABSPATH' ) || exit;

class GOFACTOX_Download {

    private const QUERY_INVOICE  = 'gofactox_download';
    private const QUERY_REFUND   = 'gofactox_download_refund';
    private const QUERY_TOKEN    = 'gofactox_token';

    public static function init(): void {
        add_action( 'init', [ __CLASS__, 'add_rewrite_rule' ] );
        add_filter( 'query_vars', [ __CLASS__, 'add_query_vars' ] );
        add_action( 'template_redirect', [ __CLASS__, 'handle_download' ] );
    }

    /**
     * Add rewrite rules for clean download URLs.
     */
    public static function add_rewrite_rule(): void {
        add_rewrite_rule(
            '^wfx-invoice/([0-9]+)/([a-f0-9]+)/?$',
            'index.php?' . self::QUERY_INVOICE . '=$matches[1]&' . self::QUERY_TOKEN . '=$matches[2]',
            'top'
        );
        add_rewrite_rule(
            '^wfx-credit-note/([0-9]+)/([a-f0-9]+)/?$',
            'index.php?' . self::QUERY_REFUND . '=$matches[1]&' . self::QUERY_TOKEN . '=$matches[2]',
            'top'
        );
    }

    /**
     * Register query vars.
     */
    public static function add_query_vars( array $vars ): array {
        $vars[] = self::QUERY_INVOICE;
        $vars[] = self::QUERY_REFUND;
        $vars[] = self::QUERY_TOKEN;
        return $vars;
    }

    /**
     * Handle the download request (invoice or credit note).
     */
    public static function handle_download(): void {
        $invoice_order_id = (int) get_query_var( self::QUERY_INVOICE );
        $refund_id        = (int) get_query_var( self::QUERY_REFUND );
        $token            = (string) get_query_var( self::QUERY_TOKEN );

        if ( ! $token ) {
            return;
        }

        if ( $invoice_order_id ) {
            self::serve_invoice( $invoice_order_id, $token );
            return;
        }

        if ( $refund_id ) {
            self::serve_credit_note( $refund_id, $token );
        }
    }

    private static function serve_invoice( int $order_id, string $token ): void {
        $order = wc_get_order( $order_id );
        if ( ! $order instanceof \WC_Order ) {
            wp_die( esc_html__( 'Invoice not found.', 'gofactox-e-invoicing-for-woocommerce' ), 404 );
        }

        $expected_token = self::generate_order_token( $order );
        if ( ! hash_equals( $expected_token, $token ) ) {
            wp_die( esc_html__( 'Invalid download link.', 'gofactox-e-invoicing-for-woocommerce' ), 403 );
        }

        self::check_permissions( $order );

        $invoice_id = (int) $order->get_meta( '_gofactox_invoice_id' );
        if ( ! $invoice_id ) {
            wp_die( esc_html__( 'No invoice found for this order.', 'gofactox-e-invoicing-for-woocommerce' ), 404 );
        }

        $pdf_path = GOFACTOX_Invoice::get_pdf_path( $invoice_id );
        if ( ! $pdf_path || ! file_exists( $pdf_path ) ) {
            wp_die( esc_html__( 'Invoice file not found.', 'gofactox-e-invoicing-for-woocommerce' ), 404 );
        }

        $number = (string) $order->get_meta( '_gofactox_invoice_number' );
        self::stream_pdf( $pdf_path, $number !== '' ? $number : 'invoice' );
    }

    private static function serve_credit_note( int $refund_id, string $token ): void {
        $refund = wc_get_order( $refund_id );
        if ( ! $refund instanceof \WC_Order_Refund ) {
            wp_die( esc_html__( 'Credit note not found.', 'gofactox-e-invoicing-for-woocommerce' ), 404 );
        }

        $expected_token = self::generate_refund_token( $refund );
        if ( ! hash_equals( $expected_token, $token ) ) {
            wp_die( esc_html__( 'Invalid download link.', 'gofactox-e-invoicing-for-woocommerce' ), 403 );
        }

        $parent_order = wc_get_order( $refund->get_parent_id() );
        if ( ! $parent_order instanceof \WC_Order ) {
            wp_die( esc_html__( 'Credit note not found.', 'gofactox-e-invoicing-for-woocommerce' ), 404 );
        }

        self::check_permissions( $parent_order );

        $cn_id = (int) $refund->get_meta( '_gofactox_credit_note_id' );
        if ( ! $cn_id ) {
            wp_die( esc_html__( 'No credit note found for this refund.', 'gofactox-e-invoicing-for-woocommerce' ), 404 );
        }

        $pdf_path = GOFACTOX_Invoice::get_pdf_path( $cn_id );
        if ( ! $pdf_path || ! file_exists( $pdf_path ) ) {
            wp_die( esc_html__( 'Credit note file not found.', 'gofactox-e-invoicing-for-woocommerce' ), 404 );
        }

        $number = (string) $refund->get_meta( '_gofactox_credit_note_number' );
        self::stream_pdf( $pdf_path, $number !== '' ? $number : 'credit-note' );
    }

    /**
     * Permission gate: admins, shop managers, or the original customer.
     */
    private static function check_permissions( \WC_Order $order ): void {
        if ( current_user_can( 'manage_woocommerce' ) ) {
            return;
        }

        $customer_id = $order->get_customer_id();
        if ( ! $customer_id || $customer_id !== get_current_user_id() ) {
            wp_die( esc_html__( 'You do not have permission to download this document.', 'gofactox-e-invoicing-for-woocommerce' ), 403 );
        }
    }

    /**
     * Stream a PDF to the browser inline.
     */
    private static function stream_pdf( string $pdf_path, string $base_name ): void {
        $filename = sanitize_file_name( $base_name ) . '.pdf';

        header( 'Content-Type: application/pdf' );
        header( 'Content-Disposition: inline; filename="' . $filename . '"' );
        header( 'Content-Length: ' . filesize( $pdf_path ) );
        header( 'Cache-Control: private, max-age=0, must-revalidate' );
        header( 'Pragma: public' );

        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_readfile -- Direct file serving for performance.
        readfile( $pdf_path );
        exit;
    }

    /**
     * Get the download URL for an order's invoice.
     */
    public static function get_download_url( \WC_Order $order ): string {
        $token = self::generate_order_token( $order );
        return home_url( '/wfx-invoice/' . $order->get_id() . '/' . $token . '/' );
    }

    /**
     * Get the download URL for a refund's credit note.
     */
    public static function get_credit_note_download_url( \WC_Order_Refund $refund ): string {
        $token = self::generate_refund_token( $refund );
        return home_url( '/wfx-credit-note/' . $refund->get_id() . '/' . $token . '/' );
    }

    private static function generate_order_token( \WC_Order $order ): string {
        return substr( wp_hash( $order->get_id() . '|' . $order->get_order_key() . '|wfx' ), 0, 16 );
    }

    private static function generate_refund_token( \WC_Order_Refund $refund ): string {
        $parent_key = '';
        $parent     = wc_get_order( $refund->get_parent_id() );
        if ( $parent instanceof \WC_Order ) {
            $parent_key = $parent->get_order_key();
        }
        return substr( wp_hash( 'cn|' . $refund->get_id() . '|' . $parent_key . '|wfx' ), 0, 16 );
    }
}
