<?php

namespace Sibs\Stargate\Gateways;

use Automattic\WooCommerce\Enums\OrderStatus;
use Sibs\Stargate\Admin\SibsPaymentSettings;
use Sibs\Stargate\Admin\SibsStyleSettings;
use Sibs\Stargate\Api\Checkout;
use Sibs\Stargate\Api\CheckStatus;
use Sibs\Stargate\Api\Refund;
use Sibs\Stargate\Api\Widget;
use Sibs\Stargate\Config\SibsConfig;
use Sibs\Stargate\Constants\PaymentStatus;
use Sibs\Stargate\Constants\Plugin;
use Sibs\Stargate\Core\SibsFunctions;
use Sibs\Stargate\Core\SibsGeneralFunctions;
use Sibs\Stargate\Exceptions\SibsException;
use Sibs\Stargate\Exceptions\StgException;
use Sibs\Stargate\Loggers\SibsLogger;
use Sibs\Stargate\Models\SibsGeneralModels;
use Sibs\Stargate\Utils\SibsNotes;
use Sibs\Stargate\Utils\TemplateUtils;
use Sibs\Stargate\Utils\UrlUtils;
use WC_Order;

defined('ABSPATH') || exit;

abstract class SibsPaymentGateway extends \WC_Payment_Gateway
{
    /**
     * Woocommerce Method.
     *
     * @var string
     */
    protected $woocommerce_method;

    /**
     * Payment Method.
     *
     * @var string
     */
    protected $payment_method;

    /**
     * Payment Type.
     *
     * @var string
     */
    protected $payment_type;

    /**
     * Language.
     *
     * @var string
     */
    protected $language;

    /**
     * Plugin URL.
     *
     * @var string
     */
    protected $plugins_url;

    /**
     * Constructor.
     */
    public function __construct()
    {
        $this->plugins_url = SibsFunctions::sibs_get_plugin_url();
        $this->form_fields = SibsPaymentSettings::sibs_create_backend_payment_settings($this->id);
        $this->method_title = SibsPaymentSettings::sibs_backend_payment_title($this->id);
        $this->method_description = SibsPaymentSettings::sibs_backend_payment_desc($this->id);
        $this->payment_type = SibsGeneralFunctions::sibs_get_payment_type($this->id);
        $this->language = SibsFunctions::get_language();
        $this->has_fields = true;

        // Enable woocommerce refund for {payment gateway}.
        $this->supports = [
            'refunds',
            'products',
            'pre-orders',
            'woocommerce_blocks',
        ];

        $this->init_settings();

        // shortcodes
        add_shortcode('sibs_shortcode_thankyou_page', [$this, 'sibs_shortcode_thankyou_page']);

        // Save admin configuration from woocomerce checkout tab.
        add_action("woocommerce_update_options_payment_gateways_{$this->id}", [$this, 'process_admin_options']); // https://wp-kama.com/plugin/woocommerce/hook/woocommerce_update_options_payment_gateways_(gateway_id)

        // Frontend hook.
        add_action("woocommerce_receipt_{$this->id}", [$this, 'sibs_stg_receipt_page']); // https://wp-kama.com/plugin/woocommerce/hook/woocommerce_receipt_(orderpayment_method)
        add_action("woocommerce_thankyou_{$this->id}", [$this, 'sibs_action_thankyou_page']); // https://wp-kama.com/plugin/woocommerce/hook/woocommerce_thankyou_(orderpayment_method)
    }

    /**
     * SIBS Get Gateway.
     */
    abstract public function get_gateway(): SibsPaymentGateway;

    /**
     * SIBS Admin Url.
     */
    abstract public function get_admin_url(): string;

    /**
     * Get Payment Method.
     *
     * @return string
     */
    public function get_payment_method()
    {
        return $this->payment_method;
    }

    /**
     * Get Payment Type.
     *
     * @return string
     */
    public function get_payment_type()
    {
        return $this->payment_type;
    }

    /**
     * Is Available.
     *
     * @return bool
     */
    public function is_available()
    {
        return parent::is_available();
    }

    /**
     * SIBS: Get Multi Icon.
     *
     * @return string
     */
    abstract public function get_multi_icon();

    /**
     * SIBS: Get Mode.
     *
     * @return string
     */
    abstract public function get_mode();

    /**
     * Get Icon.
     *
     * @return mixed
     */
    public function get_icon()
    {
        $icon_html = $this->get_multi_icon();

        if (!empty($icon_html)) {
            return apply_filters('woocommerce_gateway_icon', $icon_html, $this->id);
        }
    }

    /**
     * SIBS Shortcode Thank You Page.
     *
     * @return string
     */
    public function sibs_shortcode_thankyou_page()
    {
        $wc_order = UrlUtils::get_order_from_request();

        if (!$wc_order) {
            return '';
        }

        if ($wc_order->get_payment_method() !== $this->id) {
            return '';
        }

        try {
            $this->handle_gateway_response($wc_order);
        } catch (\Exception $e) {
            return '';
        }

        ob_start();
        $this->sibs_stg_thankyou_page_template($wc_order);

        return ob_get_clean();
    }

    /**
     * SIBS Action Thank You Page.
     *
     * @param int $order_id
     */
    public function sibs_action_thankyou_page($order_id)
    {
        $wc_order = wc_get_order($order_id);

        if (!$wc_order instanceof \WC_Order || $wc_order->get_payment_method() !== $this->id) {
            return;
        }

        $this->sibs_stg_thankyou_page_template($wc_order);
    }

    /**
     * SIBS Thank You Page.
     */
    abstract public function sibs_stg_thankyou_page_template(\WC_Order $wc_order);

    /**
     * Process Payment.
     *
     * Process the payment. Override this in your gateway. When implemented, this should.
     * return the success and redirect in an array. e.g:
     *
     *        return array(
     *            'result'   => 'success',
     *            'redirect' => $this->get_return_url( $order )
     *        );
     *
     * @param int $order_id order ID
     *
     * @return array
     */
    public function process_payment($order_id)
    {
        try {
            SibsLogger::debug('Start to Render Widget');

            $wc_order = wc_get_order($order_id);

            if (!$wc_order instanceof \WC_Order) {
                throw new \Exception('Order Id did not get an WC_Order');
            }

            // Retrieve transaction if it exists
            $existing_transaction = SibsGeneralModels::get_transaction($wc_order);

            $this->validate_checkout($existing_transaction);

            // Create a new transaction
            $transaction_data = $this->generate_transaction($wc_order);

            $transaction_id = $transaction_data['transactionID'];

            // Save transaction data in order meta
            $wc_order->set_transaction_id($transaction_id);
            $wc_order->save();

            // Mark the order as pending payment
            $wc_order->update_status(OrderStatus::PENDING, __('Awaiting payment confirmation', 'sibs-woo-stg'));

            SibsLogger::debug('End to Render Widget: Redirect to Checkout Payment Succeded');
            SibsLogger::debug('Is Using Block Checkout: '.($this->is_using_block_checkout() ? 'Yes' : 'No'));

            return [
                'result' => 'success',
                'redirect' => $wc_order->get_checkout_payment_url(true),
            ];
        } catch (\Exception $e) {
            $errorMessage = ($e instanceof SibsException) ? $e->getErrorMessage() : $e->getMessage();
            SibsLogger::error('End to Render Widget: Redirect to Checkout Payment Failed because of: '.$errorMessage);

            if (!WC()->session->has_session()) {
                WC()->session->set_customer_session_cookie(true);
            }

            $notice = ($e instanceof StgException) ? $e->getErrorMessage() : __('Unfortunately, your transaction has failed. Please try again', 'sibs-woo-stg');

            wc_clear_notices();
            wc_add_notice($notice, 'error');

            return [
                'result' => 'failure',
            ];
        }
    }

    /**
     * SIBS: Receipt Page.
     *
     * @param string $order_id
     */
    public function sibs_stg_receipt_page($order_id)
    {
        try {
            SibsLogger::debug('Receipt Page INIT: '.$order_id);

            $page_id = UrlUtils::get_request_value('page_id');
            $order_received = UrlUtils::get_request_value('order-received');
            $key = UrlUtils::get_request_value('key');

            SibsLogger::debug('order_id: '.$order_id);
            SibsLogger::debug('page_id: '.$page_id);
            SibsLogger::debug('order-received: '.$order_received);
            SibsLogger::debug('key: '.$key);

            $wc_order = wc_get_order($order_id);

            if (!$wc_order instanceof \WC_Order) {
                throw new \Exception('Order Id did not get an WC_Order');
            }

            // Get Template Parameters
            $template_parameters = $this->get_template_parameters($wc_order);

            wp_enqueue_script('sibs_form_payment_widget_script', $template_parameters['payment_widget_url'], ['jquery'], false, true);

            // Show Payment Form
            TemplateUtils::get_template('template-payment-form', 'checkout', $template_parameters);
        } catch (\Exception $e) {
            $errorMessage = ($e instanceof SibsException) ? $e->getErrorMessage() : $e->getMessage();
            $this->redirect_to_checkout_page($errorMessage);
        }
    }

    /**
     * SIBS: Call Gateway Template Redirect.
     */
    public function sibs_stg_template_redirect(\WC_Order $wc_order)
    {
        if (!is_wc_endpoint_url('order-received')) {
            return;
        }

        if (!$wc_order) {
            return;
        }

        try {
            $this->handle_gateway_response($wc_order);
        } catch (\Exception $e) {
            $this->redirect_to_checkout_page($e->getMessage());
        }
    }

    /**
     * Process refund.
     *
     * If the gateway declares 'refunds' support, this will allow it to refund.
     * a passed in amount.
     *
     * @param int        $order_id order ID
     * @param null|float $amount   refund amount
     * @param string     $reason   refund reason
     *
     * @return bool|\WP_Error true or false based on success, or a WP_Error object
     */
    public function process_refund($order_id, $amount = null, $reason = '')
    {
        $wc_order = wc_get_order($order_id);

        if (!$wc_order) {
            return new \WP_Error('invalid_order', 'Invalid order ID');
        }

        return Refund::process($wc_order, $amount, $reason);
    }

    /**
     * Validate Checkout.
     *
     * @param array $existing_transaction
     *
     * @return true
     *
     * @throws StgException
     */
    protected function validate_checkout($existing_transaction = [])
    {
        if (!empty($existing_transaction) && is_array($existing_transaction)) {
            if (PaymentStatus::SUCCESS == $existing_transaction['payment_status']) {
                throw new StgException(StgException::ERROR_ALREADY_PAID);
            }

            if (PaymentStatus::PENDING == $existing_transaction['payment_status']) {
                throw new StgException(StgException::ERROR_TRANSACTION_PENDING);
            }
        }

        return true;
    }

    /**
     * Generate Transaction.
     *
     * @return array
     *
     * @throws \Exception|\PDOException|StgException
     */
    protected function generate_transaction(\WC_Order $wc_order)
    {
        WC()->session->__unset('sibs_stg_oneclick_customer_acceptor');
        $oneclick_customer_acceptor = !empty($_POST['sibs_stg_oneclick_customer_acceptor']);
        SibsLogger::debug('Customer accept Oneclick/Tokenization: '.(($oneclick_customer_acceptor) ? 'Yes' : 'No'));
        WC()->session->set('sibs_stg_oneclick_customer_acceptor', $oneclick_customer_acceptor);

        // Get Checkout Response
        $checkoutResult = Checkout::process($wc_order, $this->id);
        $returnUrl = $this->get_return_url($wc_order);

        $formConfig = json_encode(Checkout::generateFormConfig($wc_order, $this->payment_method, $returnUrl));
        $transactionID = $checkoutResult['transactionID'] ?? null;
        $signature = $checkoutResult['transactionSignature'] ?? null;
        $spgStyle = json_encode(SibsStyleSettings::__toArray());
        $formContext = $checkoutResult['formContext'] ?? null;

        $transactionData = [
            'order_no' => $wc_order->get_id(),
            'customer_id' => $wc_order->get_customer_id() ?: null,
            'reference_id' => $transactionID,
            'captured_id' => null,
            'refunded_id' => null,
            'payment_id' => $this->id,
            'payment_type' => $this->get_mode(),
            'payment_brand' => $this->payment_method,
            'payment_status' => PaymentStatus::default(),
            'date' => SibsConfig::getStoreCurrentTime(),
            'currency' => $wc_order->get_currency(),
            'amount' => $wc_order->get_total(),
            'additional_information' => null,
            'capture_status' => null,
            'captured_amount' => 0.0,
            'capture_information' => null,
            'refund_status' => null,
            'refunded_amount' => 0.0,
            'refund_information' => null,
            'formConfig' => $formConfig,
            'signature' => $signature,
            'spg_style' => $spgStyle,
            'formContext' => $formContext,
        ];

        SibsNotes::sibs_add_customer_note($wc_order);

        $transaction_saved = SibsGeneralModels::create_or_update_transaction($transactionData);
        SibsLogger::debug('transaction_saved: '.($transaction_saved ? 'yes' : 'no'));

        CheckStatus::save_or_update_token_info($checkoutResult);

        return $checkoutResult;
    }

    /**
     * Get Template Parameters.
     *
     * @param \WC_Order wc_order
     *
     * @return array
     */
    protected function get_template_parameters(\WC_Order $wc_order)
    {
        // Widget
        $payment_widget_url = Widget::process($wc_order);
        SibsLogger::debug('Widget URL: '.$payment_widget_url);

        $transaction = SibsGeneralModels::get_transaction($wc_order);

        $templateParameters = [
            'is_user_logged_in' => is_user_logged_in(),
            'payment_widget_url' => $payment_widget_url,
            'form_context' => $transaction['formContext'],
            'form_config' => $transaction['formConfig'],
            'signature' => $transaction['signature'],
            'spg_style' => $transaction['spg_style'],
        ];

        SibsLogger::debug('Template: '.json_encode($templateParameters, JSON_PRETTY_PRINT));

        return $templateParameters;
    }

    /**
     * Redirect to Checkout Page.
     */
    protected function redirect_to_checkout_page(string $error)
    {
        SibsLogger::error($error);

        if (!WC()->session->has_session()) {
            WC()->session->set_customer_session_cookie(true);
        }

        $notice = __('There was an issue with your payment.', 'sibs-woo-stg');

        wc_clear_notices();
        wc_add_notice($notice, 'error');

        $checkout_url = UrlUtils::get_checkout_url();
        SibsLogger::debug('Redirecting to: '.$checkout_url);

        wp_safe_redirect($checkout_url);

        exit;
    }

    /**
     * Handle Gateway Response.
     */
    private function handle_gateway_response(\WC_Order $wc_order): void
    {
        SibsLogger::debug('[handle_gateway_response]');

        // Prevent double execution
        if ($wc_order->is_paid()) {
            SibsLogger::debug('Already paid, skipping');

            return;
        }

        // Prevent double execution
        if ($wc_order->get_meta('_sibs_processed')) {
            SibsLogger::debug('Already processed');

            return;
        }

        $transaction = SibsGeneralModels::get_transaction($wc_order);

        if (!$transaction) {
            throw new StgException('Transaction not found');
        }

        CheckStatus::process($wc_order);

        $wc_order->update_meta_data('_sibs_processed', true);
        $wc_order->save();

        WC()->cart->empty_cart();
    }

    /**
     * Is Using Block Checkout.
     *
     * @return bool
     */
    private function is_using_block_checkout()
    {
        // Only allow inline on checkout page
        if (!is_checkout()) {
            return false;
        }

        // If WooCommerce Blocks checkout → force inline
        if (function_exists('has_block') && has_block('woocommerce/checkout')) {
            return true;
        }

        // return IntegrationTypes::INLINE === SibsConfig::getIntegrationType();
        return false;
    }
}
