<?php

namespace Sibs\Stargate\Params;

use libphonenumber\NumberParseException;
use libphonenumber\PhoneNumberFormat;
use libphonenumber\PhoneNumberUtil;
use Sibs\Stargate\Config\SibsConfig;
use Sibs\Stargate\Constants\PaymentMethods;
use Sibs\Stargate\Constants\Plugin;
use Sibs\Stargate\Constants\Tokens;
use Sibs\Stargate\Constants\WoocommercePaymentMethods;
use Sibs\Stargate\Core\SibsFunctions;
use Sibs\Stargate\Core\SibsGeneralFunctions;
use Sibs\Stargate\Loggers\SibsLogger;
use Sibs\Stargate\Models\SibsGeneralModels;

defined('ABSPATH') || exit;

class OrderParams
{
    /**
     * Woocommerce Order.
     */
    protected \WC_Order $wc_order;

    /**
     * Construct.
     */
    public function __construct(\WC_Order $wc_order)
    {
        $this->wc_order = $wc_order;
    }

    /**
     * Main payload builder.
     */
    public function getParams(string $payment_id): array
    {
        $order_number = (string) $this->wc_order->get_order_number();
        $terminal_id = (int) SibsConfig::getTerminalId();

        $transaction_description = sprintf(
            'Transaction for order number %s terminalId %d',
            $order_number,
            $terminal_id
        );

        $base = [
            'merchant' => [
                'terminalId' => $terminal_id,
                'channel' => SibsConfig::getChannel(),
                'merchantTransactionId' => $order_number,
                'transactionDescription' => $transaction_description,
                'shopURL' => site_url('/'),
            ],
            'transaction' => [
                'transactionTimestamp' => wp_date('Y-m-d\TH:i:s.vP'),
                'description' => $transaction_description,
                'moto' => SibsConfig::getMoto(),
                'paymentMethod' => [
                    SibsGeneralFunctions::sibs_spg_get_payment_method($payment_id),
                ],
                'paymentType' => SibsGeneralFunctions::sibs_get_payment_type($payment_id),
                'amount' => [
                    'value' => (float) SibsFunctions::sibs_set_number_format($this->wc_order->get_total()),
                    'currency' => get_woocommerce_currency(),
                ],
                'forceDisableClickToPay' => (bool) SibsConfig::getForceDisableClickToPay(),
            ],
            'info' => [
                'deviceInfo' => [
                    'applicationName' => SibsConfig::getEcommerceName().':'.SibsConfig::getEcommerceVersion(),
                    'applicationVersion' => SibsConfig::getPluginVersion(),
                ],
            ],
            'customer' => [
                'customerInfo' => $this->buildCustomerInfo($payment_id),
            ],
        ];

        $payment_parameters = array_merge_recursive(
            $base,
            $this->setPaymentParameters($payment_id)
        );

        if ($this->isUserLoggedIn()) {
            $payment_parameters = array_merge_recursive(
                $payment_parameters,
                $this->getCheckoutParameterOneclick($payment_id)
            );
        }

        return $payment_parameters;
    }

    /**
     * Customer info builder.
     */
    private function buildCustomerInfo(string $payment_id): array
    {
        $customer = [
            'customerName' => trim(
                $this->wc_order->get_billing_first_name().' '.$this->wc_order->get_billing_last_name()
            ),
            'customerEmail' => $this->wc_order->get_billing_email(),
            'customerLanguage' => SibsFunctions::get_language(),
        ];

        if ($this->requiresPhone($payment_id)) {
            $phone = $this->formatPhone(
                $this->wc_order->get_billing_phone(),
                $this->wc_order->get_billing_country()
            );

            if ($phone) {
                $customer['customerPhone'] = $phone;
            }
        }

        $shipping = $this->getShippingAddress();
        if ($this->isValidAddress($shipping)) {
            $customer['shippingAddress'] = $shipping;
        }

        $billing = $this->getBillingAddress();
        if ($this->isValidAddress($billing)) {
            $customer['billingAddress'] = $billing;
        }

        return $customer;
    }

    /**
     * Requires Phone.
     */
    private function requiresPhone(string $payment_id): bool
    {
        return in_array($payment_id, [
            WoocommercePaymentMethods::BLIK,
            WoocommercePaymentMethods::PAY_BY_LINK,
            WoocommercePaymentMethods::PAY_BY_LINK_KEVIN,
        ], true);
    }

    /**
     * Format Phone.
     */
    private function formatPhone(?string $phone, ?string $countryCode): ?string
    {
        if (empty($phone)) {
            return null;
        }

        $phoneUtil = PhoneNumberUtil::getInstance();

        try {
            $number = $phoneUtil->parse($phone, $countryCode ?: null);

            if (!$phoneUtil->isValidNumber($number)) {
                return null;
            }

            $formatted = $phoneUtil->format($number, PhoneNumberFormat::E164);

            return preg_replace('/^(\+[0-9]{1,3})/', '$1-', $formatted);
        } catch (NumberParseException $e) {
            return null;
        }
    }

    /**
     * Is User Logged In.
     */
    private function isUserLoggedIn(): bool
    {
        return is_user_logged_in();
    }

    /**
     * Shipping address.
     */
    private function getShippingAddress(): array
    {
        if (!$this->wc_order->has_shipping_address()) {
            return $this->getBillingAddress();
        }

        return [
            'street1' => $this->wc_order->get_shipping_address_1(),
            'street2' => $this->wc_order->get_shipping_address_2(),
            'city' => $this->wc_order->get_shipping_city(),
            'postcode' => $this->wc_order->get_shipping_postcode(),
            'country' => $this->wc_order->get_shipping_country(),
        ];
    }

    /**
     * Billing address.
     */
    private function getBillingAddress(): array
    {
        if (!$this->wc_order->has_billing_address()) {
            return $this->getShippingAddress();
        }

        return [
            'street1' => $this->wc_order->get_billing_address_1(),
            'street2' => $this->wc_order->get_billing_address_2(),
            'city' => $this->wc_order->get_billing_city(),
            'postcode' => $this->wc_order->get_billing_postcode(),
            'country' => $this->wc_order->get_billing_country(),
        ];
    }

    private function isValidAddress(array $address): bool
    {
        return !empty($address['country']) && !empty($address['city']);
    }

    /**
     * Payment method specific parameters.
     */
    private function setPaymentParameters(string $payment_id): array
    {
        SibsLogger::debug('Payment method payload build: '.$payment_id);

        return match ($payment_id) {
            WoocommercePaymentMethods::PAY_BY_LINK,
            WoocommercePaymentMethods::PAY_BY_LINK_KEVIN => $this->buildPayByLinkParams(),
            default => [],
        };
    }

    private function buildPayByLinkParams(): array
    {
        $expiration = SibsConfig::getStoreCurrentTime('Y-m-d\TH:i:s.vP', false, false, 3, 1);

        return [
            'transaction' => [
                'payByLink' => [
                    'expirationDateTime' => $expiration,
                    'linkExpirationDateTime' => $expiration,
                ],
            ],
        ];
    }

    /**
     * OneClick / tokenization.
     */
    private function getCheckoutParameterOneclick(string $payment_id): array
    {
        $method = SibsGeneralFunctions::sibs_spg_get_payment_method($payment_id);

        if (PaymentMethods::CARD !== $method) {
            return [];
        }

        $mode = SibsConfig::getPaymentOption(WoocommercePaymentMethods::CARD, 'tokenization');

        $tokeniseCard = false;
        $customerAcceptance = false;
        $paymentTokens = [];

        switch ($mode) {
            case Tokens::TOKENIZATION:
                $tokeniseCard = true;
                $paymentTokens = SibsGeneralModels::get_current_user_card_tokens();

                break;

            case Tokens::ONECLICK:
                if (WC()->session->has_session() && WC()->session->__isset(Plugin::PLUGIN_PREFIX.'_oneclick_customer_acceptor')) {
                    $customerAcceptance = (bool) WC()->session->get(Plugin::PLUGIN_PREFIX.'_oneclick_customer_acceptor');
                    $tokeniseCard = $customerAcceptance;
                    SibsLogger::error($tokeniseCard);

                    if ($customerAcceptance) {
                        $paymentTokens = SibsGeneralModels::get_current_user_card_tokens();
                    }
                }

                break;
        }

        return [
            'transaction' => [
                'oneClick' => [
                    'customerAcceptance' => $customerAcceptance,
                ],
            ],
            'tokenisation' => [
                'tokenisationRequest' => [
                    'tokeniseCard' => $tokeniseCard,
                ],
                'paymentTokens' => $paymentTokens,
            ],
        ];
    }
}
