<?php

use YooKassa\Model\PaymentStatus;
use YooKassa\Request\Payments\Payment\CreateCaptureRequest;
use YooMoney\Helpers\DatabaseHelper;
use YooMoney\Helpers\LoggerHelper;

defined('_JEXEC') or die('Restricted access');

require_once dirname(__FILE__).'/../../../components/com_jshopping/payments/payment.php';
require_once dirname(__FILE__) . '/../../../components/com_jshopping/payments/pm_yoomoney/pm_yoomoney.php';
require_once dirname(__FILE__) . '/../../../components/com_jshopping/payments/pm_yoomoney/lib/Model/KassaSecondReceiptModel.php';

class plgJshoppingAdminPm_yoomoney extends JPlugin
{
    public function onBeforeChangeOrderStatusAdmin($order_id, &$status)
    {
        $paymentMethod = $this->getPaymentMethodTable();

        $all_payment_methods = $paymentMethod->getAllPaymentMethods();
        $pm_kassa            = null;

        foreach ($all_payment_methods as $pm) {
            $scriptName = ($pm->scriptname != '') ? $pm->scriptname : $pm->payment_class;
            if ($scriptName !== 'pm_yoomoney') {
                continue;
            }
            $pm_kassa = $pm;
            break;
        }

        if (!$pm_kassa) {
            return;
        }

        $pmconfig = $this->parsePaymentParams($pm_kassa->payment_params);

        $pm_yoomoney = new pm_yoomoney();
        $kassa = $pm_yoomoney->getKassaPaymentMethod($pmconfig);

        $pm_yoomoney->sendSecondReceipt($order_id, $kassa, $status);

        if (!$kassa->isEnableHoldMode()) {
            return;
        }

        $onHoldStatus   = $pmconfig['yookassa_hold_mode_on_hold_status'];
        $cancelStatus   = $pmconfig['yookassa_hold_mode_cancel_status'];
        $completeStatus = $pmconfig['kassa_transaction_end_status'];


        if (!in_array($status, array($completeStatus, $cancelStatus))) {
            return;
        }

        /** @var jshopOrder $order */
        $order = JSFactory::getTable('order', 'jshop');
        $order->load($order_id);

        if ($order->payment_method_id !== $pm_kassa->payment_id) {
            return;
        }

        if ($order->order_status !== $onHoldStatus) {
            return;
        }

        if ($status === $completeStatus) {
            $this->getLogger()->sendHeka(array('payment.capture.init'));
            $apiClient = $kassa->getClient();
            $payment = $apiClient->getPaymentInfo($pm_yoomoney->getOrderModel()->getPaymentIdByOrderId($order->order_id));
            try {
                $builder = CreateCaptureRequest::builder();
                $builder->setAmount($order->order_total);

                if ($kassa->isSendReceipt()) {
                    $kassa->factoryReceipt($builder, $order->getAllItems(), $order);
                }

                $request = $builder->build();
                $payment = $apiClient->capturePayment($request, $payment->getId());
                $this->getLogger()->sendHeka(array('payment.capture.success'));
            } catch (\Exception $e) {
                $pm_yoomoney->log('error', 'Capture error: ' . $e->getMessage());
                $this->getLogger()->sendAlertLog('Capture error', array(
                    'methodid' => 'POST/onBeforeChangeOrderStatusAdmin',
                    'exception' => $e,
                ), array('payment.capture.fail'));
            }

            if (!$payment || $payment->getStatus() !== PaymentStatus::SUCCEEDED) {
                $status = $onHoldStatus;
                $pm_yoomoney->saveOrderHistory($order, _JSHOP_YOO_HOLD_MODE_CAPTURE_PAYMENT_FAIL);
                $pm_yoomoney->log('error', 'Capture payment error: capture failed');
                return;
            }
            $order->order_status = $completeStatus;
            $pm_yoomoney->saveOrderHistory($order, _JSHOP_YOO_HOLD_MODE_CAPTURE_PAYMENT_SUCCESS);


            $pm_yoomoney->sendSecondReceipt($order_id, $kassa, $completeStatus);

        }

        if ($status === $cancelStatus) {
            $this->getLogger()->sendHeka(array('payment.cancel.init'));
            $apiClient = $kassa->getClient();
            $payment   = null;

            try {
                $payment = $apiClient->cancelPayment($order->transaction);
                $this->getLogger()->sendHeka(array('payment.cancel.success'));
            } catch (\Exception $e) {
                $pm_yoomoney->log('error', 'Cancel error: ' . $e->getMessage());
                $this->getLogger()->sendAlertLog('Cancel error', array(
                    'methodid' => 'POST/onBeforeChangeOrderStatusAdmin',
                    'exception' => $e,
                ), array('payment.cancel.fail'));
            }

            if (!$payment || $payment->getStatus() !== PaymentStatus::CANCELED) {
                $status = $onHoldStatus;
                $pm_yoomoney->saveOrderHistory($order, _JSHOP_YOO_HOLD_MODE_CANCEL_PAYMENT_FAIL);
                $pm_yoomoney->log('error', 'Cancel payment error: cancel failed');
                return;
            }
            $order->order_status = $cancelStatus;
            $pm_yoomoney->saveOrderHistory($order, _JSHOP_YOO_HOLD_MODE_CANCEL_PAYMENT_SUCCESS);
        }
    }

    private function parsePaymentParams($params)
    {
        if ($this->getJoomlaVersion() == 4) {
            return (array)json_decode($params, true);
        }

        return (new parseString($params))->parseStringToParams();
    }

    /**
     * @return int
     */
    private function getJoomlaVersion()
    {
        $version = (version_compare(JVERSION, '3.0', '<') == 1) ? 2 : 3;
        return (version_compare(JVERSION, '4.0', '<') == 1) ? $version : 4;
    }


    /**
     * Получение таблицы платежных методов
     *
     * @return mixed
     */
    private function getPaymentMethodTable()
    {
        return JSFactory::getTable('paymentmethod', 'jshop');
    }

    /**
     * Обработка события перед сохранением модели платежного метода
     *
     * @param array $post
     * @return void
     * @throws Exception
     */
    public function onBeforeSavePayment(&$post)
    {
        $this->getLogger()->sendHeka(array('settings.save.init'));

        if ($post['payment_class'] === 'pm_yoomoney_sbbol') {
            $this->getLogger()->sendHeka(array('settings.save.success'));
            return;
        }

        $payment = $this->getPaymentMethodTable();

        if (!$payment) {
            $this->getLogger()->sendHeka(array('settings.save.fail'));
            return;
        }

        $payment->load($post['payment_id']);

        $paymentParamsFromDB = $this->parsePaymentParams($payment->payment_params);

        $this->addFieldsToFormArray($post, $paymentParamsFromDB);
        $this->replaceWebhooksUrl($post);

        $this->getLogger()->sendHeka(array('settings.save.success'));
    }

    /**
     * Добавление отсутствующих в форме данных по oauth
     *
     * @param array $post
     * @param array $paymentParamsFromDB
     * @return void
     */
    private function addFieldsToFormArray(&$post, $paymentParamsFromDB)
    {
        $nameFieldForSave = array(
            'shop_id',
            'state',
            'access_token',
            'expires_in'
        );

        $oauthDataArray = array();
        foreach ($paymentParamsFromDB as $key => $value) {
            if (in_array($key, $nameFieldForSave)) {
                $oauthDataArray[$key] = $value;
            }
        }

        $post['pm_params'] = array_merge($post['pm_params'], $oauthDataArray);
    }

    /**
     * Замена url вебхуков
     *
     * @param array $post
     * @return void
     * @throws Exception
     */
    private function replaceWebhooksUrl(&$post)
    {
        $isChangeUrl = (bool) $post['pm_params']['yookassa_new_url'];
        $notificationUrlNew = $post['pm_params']['notification_url'];
        unset($post['pm_params']['notification_url'], $post['pm_params']['yookassa_new_url']);
        if (!isset($post['pm_params']['kassamode']) || !$isChangeUrl) {
            return;
        }
        $pm_yoomoney = new pm_yoomoney();
        $webhookHelper = $pm_yoomoney->getOauthWebhooksHelper();

        try {
            $pm_yoomoney->log('info', 'Notification URL changed. Replacing webhooks.');
            $webhookHelper->replaceWebhooksWithNewUrl($notificationUrlNew);
        } catch (Exception $e) {
            $pm_yoomoney->log('error', 'Failed to replace webhooks URL: '.$e->getMessage());
            return;
        }
    }

    /**
     * @return LoggerHelper
     */
    private function getLogger()
    {
        return new LoggerHelper((new DatabaseHelper())->getPmConfig()['shop_id'] ?: null);
    }

}
