<?php

namespace RTMCustomMails\PDFInvoices;

use RTMCustomMails\Util;
use Timber\Timber;
use WC_Email;
use WC_Order_Item;
use WC_Order_Item_Product;
use WordpressModels\Traits\SingletonTrait;
use WPO\WC\PDF_Invoices\Admin;
use WPO\WC\PDF_Invoices\Documents\Order_Document;
use WPO_WCPDF;
use function WPO_WCPDF;

/**
 *
 */
class WoocommercePDFInvoices
{

    use SingletonTrait;


    private ?Order_Document $document = null;
    private array $contextCache;

    private function __construct()
    {
        add_action('wpo_wcpdf_before_html', [$this, 'registerTimberContextHook'], PHP_INT_MAX - 1, 2);
        add_action('wpo_wcpdf_after_html', [$this, 'deregisterTimberContextHook'], 10, 2);

        add_filter('wpo_wcpdf_document_classes', [$this, 'replaceWpoWcPDFIcons'], 100);

        add_action('plugins_loaded', [$this, 'resetOrderActionMeta']);

        add_filter('wrce_attached_documents', [$this, 'getWpoPdfDocumentsForEmail'], 10, 2);
    }

    public function getWpoPdfDocumentsForEmail(array $documents, WC_Email $email): array
    {
        if (!function_exists('WPO_WCPDF')) {
            return $documents;
        }
        $documents = WPO_WCPDF::instance()->documents->get_documents('all');
        $emailDocuments = array_reduce($documents, function ($carry, $doc) use ($email) {
            if (isset($doc->get_setting('attach_to_email_ids')[$email->id])) {
                $carry[] = $doc;
            }
            return $carry;
        }, []);

        return array_merge($documents, $emailDocuments);
    }

    /**
     * @param $classes
     * @return mixed
     */
    public function replaceWpoWcPDFIcons($classes): mixed
    {
        $classes['\WPO\WC\PDF_Invoices\Documents\Credit_Note']->icon = WRCE_ASSETS_URL . '/images/file-invoice-dollar.svg';
        $classes['\WPO\WC\PDF_Invoices\Documents\Invoice']->icon = WRCE_ASSETS_URL . '/images/file-invoice.svg';
        $classes['\WPO\WC\PDF_Invoices\Documents\Proforma']->icon = WRCE_ASSETS_URL . '/images/file-invoice.svg';
        $classes['\WPO\WC\PDF_Invoices\Documents\Packing_Slip']->icon = WRCE_ASSETS_URL . '/images/boxes-packing.svg';

        return $classes;
    }

    /**
     * @return void
     */
    public function deregisterTimberContextHook(): void
    {
        $this->document = null;
        remove_filter('timber/context', [$this, 'injectTimberContext'], 100);

        // restore old timber context
        Timber::$context_cache = $this->contextCache;
    }

    /**
     * @param string $type
     * @param Order_Document $document
     * @return void
     */
    public function registerTimberContextHook($type, $document): void
    {
        $this->document = $document;

        add_filter('timber/context', [$this, 'injectTimberContext'], 100);

        // temporarily reset context cache
        $this->contextCache = Timber::$context_cache;
        Timber::$context_cache = [];
    }

    public function injectTimberContext(array $context): array
    {
        $getters = Util::getClassMethods($this->document, 'get_', ['html', 'pdf']);

        // invoke all getters on document
        $ctx = Util::invokeClassMethods($getters, 'get_', $this->document);

        $order = $this->document->order;
        $ctx['order'] = $order;
        $ctx['document'] = $this->document;
        $ctx['chained_products'] = array_reduce($order->get_items(), function (array $carry, WC_Order_Item $item) {
            if ($item instanceof WC_Order_Item_Product
                && is_array($chained = $item->get_product()->get_meta('_chained_product_detail'))) {
                $carry += array_keys($chained);
            }

            return $carry;
        }, []);
        $ctx['woocommerce_weight_unit'] = get_option('woocommerce_weight_unit');

        if ($payment_reference = apply_filters('buckaroo_payment_reference', $order)) {
            $ctx['payment_reference'] = $payment_reference;
        }

        return array_merge($context, $ctx);
    }

    /**
     * @param $emailId
     * @return array
     */
    public static function getDocumentsForEmail($emailId): array
    {
        if (class_exists('\WPO_WCPDF')) {
            $allDocuments = WPO_WCPDF::instance()->documents->get_documents();
            return array_filter($allDocuments, fn($doc) => in_array($emailId, $doc->get_attach_to_email_ids()));
        }

        return [];
    }

    public static function getAvailableDocumentsForEmail(string $emailId): array
    {
        $email = Util::getEmailById($emailId);
        return apply_filters('wrce_allowed_attachments/object_type=' . $email->getObjectType(), []);
    }

    public static function getDocuments(): array
    {
        if (class_exists('\WPO_WCPDF')) {
            return WPO_WCPDF::instance()->documents->get_documents();
        }

        return [];
    }

    public function resetOrderActionMeta(): void
    {
        if (!function_exists('WPO_WCPDF')) {
            return;
        }
        /** @var Admin $wcPdfAdmin */
        $wcPdfAdmin = WPO_WCPDF()->admin;
        $removed = remove_action('woocommerce_process_shop_order_meta', [$wcPdfAdmin, 'send_emails'], 60);
        if ($removed) {
            add_action('woocommerce_process_shop_order_meta', [$this, 'sendEmails'], 60);
        }
    }

    /**
     * Copied from WPO_WCPDF\Admin. Modified to not place an order note when the emails failed to send.
     *
     *
     * @param $post_id
     * @return void
     */
    public function sendEmails($post_id): void
    {
        if (!empty($_POST['wpo_wcpdf_send_emails'])) {
            $order = wc_get_order($post_id);
            $action = wc_clean($_POST['wpo_wcpdf_send_emails']);
            if (str_contains($action, 'send_email_')) {
                $email_to_send = str_replace('send_email_', '', $action);
                // Switch back to the site locale.
                wc_switch_to_site_locale();
                do_action('woocommerce_before_resend_order_emails', $order, $email_to_send);
                // Ensure gateways are loaded in case they need to insert data into the emails.
                WC()->payment_gateways();
                WC()->shipping();
                // Load mailer.
                $mail = Util::getEmailById($email_to_send);

                if (!$mail) {
                    return;
                }
                $mail->trigger($order->get_id(), $order);

                if ($mail->getLastResult()) {
                    /* translators: %s: email title */
                    $order->add_order_note(sprintf(esc_html__('%s email notification manually sent.', 'woocommerce-pdf-invoices-packing-slips'), $mail->get_title()), false, true);
                }

                do_action('woocommerce_after_resend_order_email', $order, $email_to_send);
                // Restore user locale.
                wc_restore_locale();
                // Change the post saved message.
                add_filter('redirect_post_location', function ($location) {
                    // messages in includes/admin/class-wc-admin-post-types.php
                    // 11 => 'Order updated and sent.'
                    return esc_url_raw(add_query_arg('message', 11, $location));
                });
            }
        }
    }

}