<?php

namespace SoftminalB2B\Services\Pdf;

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

use SoftminalB2B\Services\Settings;

/**
 * Wires PDF invoices into WooCommerce (FEATURES G4): a secure download for the
 * admin and the buyer, and an optional attachment on order emails.
 */
class Invoices
{
    private const ACTION = 'smb2b_invoice';

    private static bool $registered = false;

    public static function init(): void
    {
        if (self::$registered) {
            return;
        }

        self::$registered = true;

        // If a dedicated PDF-invoice plugin is active, stay out of its way
        // rather than producing a duplicate document (G4 acceptance).
        if (self::conflictingPluginActive() && Settings::get('invoices_enabled') !== 'yes') {
            return;
        }

        if (Settings::get('invoices_enabled') === 'no') {
            return;
        }

        add_action('admin_post_' . self::ACTION, [self::class, 'handleDownload']);
        add_action('admin_post_nopriv_' . self::ACTION, [self::class, 'denyGuest']);

        // Buyer download from My Account order actions.
        add_filter('woocommerce_my_account_my_orders_actions', [self::class, 'orderAction'], 10, 2);

        // Admin download button on the order screen.
        add_action('woocommerce_admin_order_data_after_order_details', [self::class, 'adminButton']);

        // Attach to the configured order emails.
        add_filter('woocommerce_email_attachments', [self::class, 'attach'], 10, 3);
    }

    public static function conflictingPluginActive(): bool
    {
        return class_exists('WPO_WCPDF') || function_exists('wpo_wcpdf_output_pdf');
    }

    /**
     * A signed download URL for one order. The nonce is bound to the order id,
     * so a link for one order cannot be replayed against another.
     */
    public static function url(int $orderId): string
    {
        return add_query_arg(
            [
                'action'   => self::ACTION,
                'order_id' => $orderId,
                '_wpnonce' => wp_create_nonce(self::ACTION . ':' . $orderId),
            ],
            admin_url('admin-post.php')
        );
    }

    public static function handleDownload(): void
    {
        $orderId = isset($_GET['order_id']) ? absint($_GET['order_id']) : 0;
        $nonce   = isset($_GET['_wpnonce']) ? sanitize_text_field(wp_unslash($_GET['_wpnonce'])) : '';

        if ($orderId <= 0 || !wp_verify_nonce($nonce, self::ACTION . ':' . $orderId)) {
            wp_die(esc_html__('That invoice link is not valid.', 'softminal-b2b-wholesale-for-woocommerce'), '', ['response' => 400]);
        }

        $order = wc_get_order($orderId);

        if (!$order || !self::userCanView($order)) {
            wp_die(esc_html__('You are not allowed to view that invoice.', 'softminal-b2b-wholesale-for-woocommerce'), '', ['response' => 403]);
        }

        $invoice = new Invoice($order);
        $pdf     = $invoice->pdf();

        if ($pdf === '') {
            wp_die(esc_html__('The invoice could not be generated.', 'softminal-b2b-wholesale-for-woocommerce'), '', ['response' => 500]);
        }

        nocache_headers();
        header('Content-Type: application/pdf');
        header('Content-Disposition: inline; filename="' . $invoice->filename() . '"');
        header('Content-Length: ' . strlen($pdf));

        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Binary PDF stream.
        echo $pdf;
        exit;
    }

    public static function denyGuest(): void
    {
        wp_die(esc_html__('Please log in to download this invoice.', 'softminal-b2b-wholesale-for-woocommerce'), '', ['response' => 401]);
    }

    /**
     * The order's own customer, or anyone who can manage the shop.
     */
    private static function userCanView(\WC_Order $order): bool
    {
        if (current_user_can('manage_woocommerce')) {
            return true;
        }

        $customerId = $order->get_customer_id();

        return $customerId > 0 && get_current_user_id() === $customerId;
    }

    /**
     * @param array<string, array<string, string>> $actions
     * @return array<string, array<string, string>>
     */
    public static function orderAction($actions, $order)
    {
        if ($order instanceof \WC_Order) {
            $actions['smb2b_invoice'] = [
                'url'  => self::url($order->get_id()),
                'name' => __('Invoice (PDF)', 'softminal-b2b-wholesale-for-woocommerce'),
            ];
        }

        return $actions;
    }

    public static function adminButton($order): void
    {
        if (!$order instanceof \WC_Order) {
            return;
        }

        printf(
            '<p class="form-field form-field-wide"><a href="%s" class="button" target="_blank">%s</a></p>',
            esc_url(self::url($order->get_id())),
            esc_html__('Download B2B invoice (PDF)', 'softminal-b2b-wholesale-for-woocommerce')
        );
    }

    /**
     * Attach the invoice to the configured emails (default: the customer's
     * completed and processing notifications).
     *
     * @param array<int, string> $attachments
     * @param string             $emailId
     * @return array<int, string>
     */
    public static function attach($attachments, $emailId, $order)
    {
        if (!$order instanceof \WC_Order) {
            return $attachments;
        }

        // Default to the processing ("order received") email as well as completed:
        // B2B buyers on net terms / bank transfer need the invoice at order time,
        // not weeks later. Merchants can narrow this in settings.
        $configured = Settings::get('invoice_attach_emails', 'customer_processing_order,customer_completed_order');
        $enabled    = array_filter(array_map('trim', explode(',', (string) $configured)));

        if (!in_array($emailId, $enabled, true)) {
            return $attachments;
        }

        $path = (new Invoice($order))->toTempFile();

        if ($path !== null) {
            $attachments[] = $path;
        }

        return $attachments;
    }
}
