<?php

namespace App\Billingo\WooCommerce\Traits;

use App\Billingo\Enums\Document\TypeEnum;
use App\Billingo\Service\BillingoClient;
use App\Billingo\WooCommerce\Controllers\Billingo_Controller;
use App\Billingo\WooCommerce\Repositories\Billingo_Repositroy;
use App\Billingo\WooCommerce\Service\Billingo_Document_Generator;
use App\Billingo\WooCommerce\Service\Billingo_Logger;
use App\Billingo\WooCommerce\Service\Invoice_Generation_Container;
use App\Billingo\WooCommerce\Service\Billingo_Checkout_Fields;
use Symfony\Component\HttpFoundation\Response;
use WC_Order;

trait Standard_Init
{

    public static function init_hooks(): void
    {
        foreach (wc_get_order_statuses() as $status => $name) {
            $status = str_replace('wc-', '', $status);
            add_action('woocommerce_order_status_' . $status, [self::class, 'on_order_state_change'], 10);
        }
        new WC_Order();
        //add_action('woocommerce_thankyou_order_received_text', [self::class, 'action_woocommerce_email_before_order_table'], 10, 1);
        add_action('wp_ajax_wc_billingo_generate_invoice', [self::class, 'ajax_generateInvoice']);
        add_action('wp_ajax_wc_billingo_storno_invoice', [self::class, 'ajax_stornoInvoice']);
        add_action('woocommerce_email_before_order_table', [self::class, 'action_woocommerce_email_before_order_table'], 1, 4);
        //add_action('woocommerce_email_before_order_table', [self::class, 'action_woocommerce_email_before_order_table'], 20, 4);

        // 1 thankyou-ra should-proforma generate by payment method státusztól függetlenül
        add_action('woocommerce_thankyou', [self::class, 'should_proforma_generate'], 10, 1);
        // 2 automata díjbekérőt csak akkor generáljunk, ha az automata számla generálás státusz


        // Initialize product price saving hooks (always needed for orders)
        Billingo_Checkout_Fields::init_product_price_hooks();
    }

    /**
     * Processes automatic document operations
     *
     * @param integer $order_id ID of the order that is linked to the document
     */
    public static function on_order_state_change($order_id): void
    {
        Billingo_Logger::info('on_order_state_change triggered for order ID: ' . $order_id);
        $invoice_generation_data = self::collect_invoice_generation_data($order_id);

        // Generate proforma/draft if needed, removed because of the thankyou hook
        //self::should_proforma_generate($order_id);

        if (self::should_document_generate($invoice_generation_data)) {
            Billingo_Logger::startDocumentum();

            $document = $invoice_generation_data->getDocumentGenerator()->get();
            if (!is_null($document)) {
                $invoice_generation_data->getController()->createDocument($document);
            }

            Billingo_Logger::endDocumentum();
        }

        if (self::should_cancel_document($invoice_generation_data)) {
            Billingo_Logger::info('should_cancel_document triggered for order ID: - ' . $order_id);
            Billingo_Logger::startDocumentum();
            $billingo_document = $invoice_generation_data->getRepositroy()
                ->where('type', TypeEnum::INVOICE->value)
                ->where('order_id', $order_id)
                ->first();

            if (!is_null($billingo_document)) {
                $invoice_generation_data->getController()->cancelDocument($billingo_document['billingo_id']);
            }

            Billingo_Logger::endDocumentum();
        }
    }

    /**
     * Megnézzük, hogy be van -e kapcsolva a díjbekérő vagy piszkozat generálás, ha igen akkor a rendeléshez tartozó fizetési módnál megnézzük, hogy be van -e kapcsolva a díjbekérő generálása. Ha mindkét opció be van kapcsolva, akkor a díjbekérőt generál.
     *
     * @param integer $order_id ID of the order that is linked to the document
     */
    public static function should_proforma_generate($order_id): void
    {
        $invoice_generation_data = self::collect_invoice_generation_data($order_id);
        $order = wc_get_order($order_id);

        $payment_method_proforma_enabled = false;

        //megnézzük, hogy szeretne-e egyáltalán generálni díjbekérőt a felhasználó
        if (get_option('wc_billingo_payment_request_auto') !== 'no') {
            $payment_method = $order->get_payment_method();
            Billingo_Logger::info('Checking payment method for proforma: ' . $payment_method);

            // ellenőrizzük, hogy a fizetési módnál be van -e kapcsolva a díjbekérő generálása
            $payment_method_proforma_setting = get_option('wc_billingo_proforma_' . $payment_method);
            $payment_method_proforma_enabled = wcFlexibleIsTrue($payment_method_proforma_setting);
        }

        //ha be van kapcsolva a díjbekérő generálása és a fizetési módnál be van kapcsolva a díjbekérő generálása akkor megnézzük, hogy már generálva van -e a díjbekérő vagy piszkozat,
        //ez azért fontos, mert ha már van generálva, akkor nem generáljuk le újra, hogy ne legyen több díjbekérő a rendeléshez, mert a woocommerce_thankyou hook meghívódhat az oldal frissítésekor is
        if ($payment_method_proforma_enabled) {
            $type = get_option('wc_billingo_payment_request_auto') === TypeEnum::PROFORMA->value
                ? 'getProforma'
                : 'getDraft';
            $billingo_document = (new Billingo_Repositroy())
                ->where('order_id', $order_id)
                ->where('type', get_option('wc_billingo_payment_request_auto') === TypeEnum::PROFORMA->value
                    ? TypeEnum::PROFORMA->value
                    : TypeEnum::DRAFT->value)
                ->first();

            //ha nincs még generálva a díjbekérő vagy piszkozat, akkor generáljuk
            if (!$billingo_document) {
                Billingo_Logger::info( $type . ' generating for payment method: ' . $payment_method);

                Billingo_Logger::startDocumentum();
                $document = $invoice_generation_data->getDocumentGenerator()->$type();

                if (!is_null($document)) {
                    $invoice_generation_data->getController()->createDocument($document);
                }

                Billingo_Logger::endDocumentum();
            } else {
                //ha már generálva van a díjbekérő vagy piszkozat, akkor nem generáljuk újra
                Billingo_Logger::info( $type . ' is already generated for payment method: ' . $payment_method);
            }


        }
    }

    public static function ajax_stornoInvoice(): void
    {
        check_ajax_referer('wc_storno_invoice', 'nonce');

        if (!current_user_can('edit_shop_orders')) {
            wp_die(esc_html__('You do not have sufficient permissions to access this page.', 'billingo'));
        }

        $billingo_repository = new Billingo_Repositroy();
        if(!isset($_POST['order'])) {
            wp_send_json_error(['error' => true, 'messages' => __('A rendelés ID nincs megadva', 'billingo')]);
        } else {
            $order_id = (int)$_POST['order'];
        }

        // Get the order to retrieve the billing email
        $order = wc_get_order($order_id);
        if (!$order) {
            wp_send_json_error(['error' => true, 'messages' => __('A rendelés nem található', 'billingo')]);
        }

        $row_in_db = $billingo_repository
            ->where('order_id', $order_id)
            ->where('type', TypeEnum::INVOICE->value)
            ->first();
        $billingo_id = $row_in_db['billingo_id'];
        $response = ['error' => false];
        $client = new BillingoClient(get_option('wc_billingo_api_key'));

        //handles the email sending for the storno because it is not a document genaration, just a cancellation request to the server
        if(in_array(get_option('wc_billingo_storno_email'), ['both', 'billingo'])) {
            $cancellationData = [
                'cancellation_recipients' => $order->get_billing_email()
            ];

            Billingo_Logger::info('Cancelling invoice with email notification to: ' . $order->get_billing_email());

            $billingoResponse = $client->document()->cancelDocument($billingo_id, $cancellationData)->getResponse();
        }else{
            $billingoResponse = $client->document()->cancelDocument($billingo_id)->getResponse();
        }

        if ($billingoResponse->getStatusCode() === Response::HTTP_OK ) {
            $data = $billingoResponse->getData();


            $response['messages'][] =
                __('Számla sztornózva: ', 'billingo') . $data->invoice_number;

            $billingo_repository->update($row_in_db['id'], ['canceled_by' => $data->id]);
            $new_db_row = $billingo_repository->createFromDocument($order_id, $data);
            Billingo_Logger::info('Invoice cancel data: ' . json_encode($data->toArray()));

            Billingo_Logger::info('Invoice cancel SUCCESFULL:' . $new_db_row['id']);
        }else if ( $client->document()->getById($billingo_id)->getResponse()->getData()->toArray()['cancelled']){
            $response['messages'][] =
                __('Számla sztornózva a Billingóban: ', 'billingo');

            $billingo_repository->update($row_in_db['id'], ['canceled_by' => 999999999]);

            Billingo_Logger::info('Invoice already cancelled!');
        }else {
            Billingo_Logger::error('Invoice cancel FAILED:' . json_encode($billingoResponse->getErrors()));

            wp_send_json_error([
                'error'    => true,
                'messages' => [ __('A számla sztornózása sikertelen', 'billingo') ]
            ]);
        }

        wp_send_json_success($response);
    }

    public static function ajax_generateInvoice(): void
    {
        check_ajax_referer('wc_storno_invoice', 'nonce');

        if (!current_user_can('edit_shop_orders')) {
            wp_die(esc_html__('You do not have sufficient permissions to access this page.', 'billingo'));
        }
        if(!isset($_POST['order'])) {
            wp_send_json_error(['error' => true, 'messages' => __('A rendelés ID nincs megadva', 'billingo')]);
        } else {
            $orderId = (int)$_POST['order'];
            update_post_meta($orderId, '_is_manual', 'yes');
        }

        Billingo_Logger::info('ajax_generateInvoice raw POST data for wc_billingo_invoice_type: ' . ($_POST['wc_billingo_invoice_type'] ?? 'NOT SET'));
        Billingo_Logger::info('ajax_generateInvoice full relevant POST data: ' . json_encode([
                'order' => $_POST['order'] ?? null,
                'wc_billingo_invoice_type' => $_POST['wc_billingo_invoice_type'] ?? null,
                'wc_billingo_invoice_note' => $_POST['wc_billingo_invoice_note'] ?? null,
                'wc_billingo_invoice_deadline' => $_POST['wc_billingo_invoice_deadline'] ?? null,
                'wc_billingo_invoice_completed' => $_POST['wc_billingo_invoice_completed'] ?? null,
            ]));

        $response['error'] = false;

        $manualIncome = [];
        if (isset($_POST['wc_billingo_invoice_type']) && !empty($_POST['wc_billingo_invoice_type'])) {
            $manualIncome['invoice_type'] = sanitize_text_field($_POST['wc_billingo_invoice_type']);
        }
        if (isset($_POST['wc_billingo_invoice_note'])) {
            $manualIncome['note'] = sanitize_text_field($_POST['wc_billingo_invoice_note']);
        }
        if (isset($_POST['wc_billingo_invoice_deadline']) && !empty($_POST['wc_billingo_invoice_deadline'])) {
            $manualIncome['deadline'] = (int)$_POST['wc_billingo_invoice_deadline'];
        }
        if (isset($_POST['wc_billingo_invoice_completed']) && !empty($_POST['wc_billingo_invoice_completed'])) {
            $manualIncome['completed'] = sanitize_text_field($_POST['wc_billingo_invoice_completed']);
        }

        $invoice = (new Billingo_Document_Generator($orderId, $manualIncome))->get();
        if (is_null($invoice)) {
            $response['error'] = true;
            $response['messages'] = [
                __('Sikertelen generálás', 'billingo'),
                __('A rendelés adatai hiányosak, vagy hibát tartalmaznak', 'billingo'),
            ];
        } else {
            $controller = new Billingo_Controller($orderId);
            $created = $controller->createDocument($invoice);

            if (is_null($created)) {
                $response['error'] = true;
                $response['messages'] = [
                    __('Sikertelen generálás', 'billingo'),
                    __('A rendelés adatai hiányosak, vagy hibát tartalmaznak', 'billingo'),
                ];
            } else {
                $response['messages'] = [
                    __('Sikeres generálás', 'billingo'),
                    __('A bizonylat száma:', 'billingo') . $created->invoice_number,
                ];

                $document = (new Billingo_Repositroy())->where('billingo_id', $created->id)->first();
                if ($document && isset($document['link'])) {
                    $response['link'] = '<p><a href="'
                        . esc_url($document['link'])
                        . '" id="wc_billingo_download" class="button button-primary" target="_blank">'
                        . __('Bizonylat megtekintése', 'billingo')
                        . '</a></p>';
                }
            }
        }

        wp_send_json_success($response);
    }

    /**
     * Extends order notification e-mail with document link
     *
     * @param WC_Order $order
     * @param boolean $sent_to_admin
     * @param string $plain_text
     * @param boolean $email
     */
    public static function action_woocommerce_email_before_order_table(
        WC_Order $order,
        bool     $sent_to_admin,
        string   $plain_text,
                 $email = false
    ): void
    {
        if (!$email) {

            return;
        }

        Billingo_Logger::info('action_woocommerce_email_before_order_table triggered for email ID: ' . $email->id);

        $repository = new Billingo_Repositroy();

        $text = '';
        $btn_text = '';
        $pdf_link = false;
        $email_id = $email->id;

        if (is_object($order)) {
            if (method_exists($order, 'get_id')) {
                $order_id = $order->get_id();
            } elseif (property_exists($order, 'ID')) {
                $order_id = $order->ID;
            } elseif (method_exists($order, 'ID')) {
                $order_id = $order->ID();
            } else {
                $order_id = null; // vagy dobj hibát
            }
        }

        // invoice
        if (in_array(get_option('wc_billingo_email'), ['attach', 'both'])
            && in_array($email_id, [
                'customer_on_hold_order',
                'customer_completed_order',
                'customer_completed_renewal_order',
                'customer_completed_switch_order'
            ])) {
            Billingo_Logger::info('invoice email through woocommerce triggered');
            $pdf_link = $repository
                ->where('order_id', $order_id)
                ->where('type', TypeEnum::INVOICE->value)
                ->first();

            $pdf_link = $pdf_link ? $pdf_link['link'] : null;

            $text = get_option(
                'wc_billingo_email_woo_text',
                __('Számlája elkészült, melyet az alábbi linken tud megtekinteni.', 'billingo'));
            $btn_text = get_option('wc_billingo_email_woo_btn', __('Bizonylat megtekintése', 'billingo'));
        }
        // storno TODO: refactor this storno email attachment and generate storno if storno not exists (this whole if)
        //the solution is for problem: storno_document didnt exists in db at the time on the storno email sending
        //and the other problem in this part of the code the order status is 'processing', and the Invoice_Generation_Container dosent return with the cancellaction, so we need to generate it manually
        if (in_array(get_option('wc_billingo_storno_email'), ['attach', 'both'])
            && $email_id == 'customer_refunded_order'
            && get_option('wc_billingo_auto_storno') !== 'no') {
            Billingo_Logger::info('storno email through woocommerce triggered //storno email -before order table');

            // Check if storno document already exists
            $existing_storno = $repository
                ->where('order_id', $order_id)
                ->where('type', TypeEnum::CANCELLATION->value)
                ->first();

            // If storno doesn't exist yet, generate it immediately
            // For refunded order emails, we force generate storno regardless of order status
            if (!$existing_storno) {
                Billingo_Logger::info('Generating storno document for customer_refunded_order email, order: ' . $order_id);
                $invoice_generation_data = self::collect_invoice_generation_data($order_id);

                Billingo_Logger::startDocumentum();
                $billingo_document = $invoice_generation_data->getRepositroy()
                    ->where('type', TypeEnum::INVOICE->value)
                    ->where('order_id', $order_id)
                    ->first();

                if (!is_null($billingo_document)) {
                    $invoice_generation_data->getController()->cancelDocument($billingo_document['billingo_id']);
                }
                Billingo_Logger::endDocumentum();
            }

            $pdf_link = $repository
                ->where('order_id', $order_id)
                ->where('type', TypeEnum::CANCELLATION->value)
                ->first();

            $pdf_link = $pdf_link ? $pdf_link['link'] : null;

            $text = get_option('wc_billingo_storno_email_woo_text',
                __('Storno számlája elkészült, melyet az alábbi linken tud megtekinteni.', 'billingo'));
            $btn_text = get_option('wc_billingo_storno_email_woo_btn', __('Storno számla megtekintése','billingo'));
        }

        // proforma
        if (in_array(get_option('wc_billingo_proforma_email'), ['attach', 'both'])
            && in_array($email_id, ['customer_processing_order', 'customer_on_hold_order'])) {
            Billingo_Logger::info('proforma email through woocommerce triggered');
            $pdf_link = $repository
                ->where('order_id', $order_id)
                ->where('type', TypeEnum::PROFORMA->value)
                ->first();

            $pdf_link = $pdf_link ? $pdf_link['link'] : null;

            //if the proforma is not generated, we generate it with the should_proforma_generate function
            if (!$pdf_link) {
                self::should_proforma_generate($order_id);
                //sleep for 1 second waiting for the proforma to be generated, because this function is a void function and it does not return the document
                sleep(1);
                $pdf_link = $repository
                    ->where('order_id', $order_id)
                    ->where('type', TypeEnum::PROFORMA->value)
                    ->first();
                $pdf_link = $pdf_link ? $pdf_link['link'] : null;
            }

            $text = get_option('wc_billingo_proforma_email_woo_text',
                __('Díjbekérője elkészült, melyet az alábbi linken tud megtekinteni.', 'billingo'));
            $btn_text = get_option('wc_billingo_proforma_email_woo_btn', __('Díjbekérő megtekintése', 'billingo'));
        }

        if (!$pdf_link) {
            return;
        }

        echo view('Admin.billingo_invoice_link_button', [
            'text' => $text,
            'btnText' => $btn_text,
            'pdfLink' => $pdf_link,
        ]);
    }

    private static function collect_invoice_generation_data(int $order_id): Invoice_Generation_Container
    {
        return new Invoice_Generation_Container($order_id);
    }

    private static function should_document_generate(Invoice_Generation_Container $invoice_generation_data): bool
    {
        return $invoice_generation_data->getStatus() === $invoice_generation_data->getActivationStatus();
    }

    private static function should_cancel_document(Invoice_Generation_Container $invoice_generation_data): bool
    {
        return $invoice_generation_data->getStatus() === $invoice_generation_data->getAutoStornoStatus();
    }
}
