<?php

namespace Shm\ShmPayment\TBankPayment;



use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Psr7\Request;
use Shm\Shm;
use Shm\ShmAuth\Auth;
use Shm\ShmCmd\Cmd;
use Shm\ShmDB\mDB;
use Shm\ShmPayment\TBankPayment\TBankCollections\TCustomerCards;
use Shm\ShmPayment\TBankPayment\TBankCollections\TCustomerCardsField;
use Shm\ShmPayment\TBankPayment\TBankCollections\TPayments;
use Shm\ShmPayment\TBankPayment\TBankCollections\TPaymentsField;
use Shm\ShmRPC\ShmRPC;
use Shm\ShmTypes\StructureType;
use Shm\ShmUtils\ShmTwig;
use Shm\ShmUtils\ShmUtils;

class TBankPayment
{


    const API_ENDPOINT = 'https://securepay.tinkoff.ru/v2/';

    const WEBHOOK_URL = '/webhook/tbank/payment';

    //TODO не понятно придет ли 10 рублей на счет или 9,70
    //Чуть позже проверить и если не 10 рублей то считать сколько придет
    const BANK_COMMISSION = 0.03;

    protected static  $default_http_client_options = [
        'connect_timeout' => 4,
        'timeout' => 10,
        'verify' => false,
    ];

    public static $terminalKey = null;
    public static $terminalPassword =  null;


    /**
     * Система налогообложения
     * osn - общая СН
     * usn_income - упрощенная СН (доходы)
     * usn_income_outcome - упрощенная СН (доходы минус расходы)
     * esn - единый сельскохозяйственный налог
     * patent - патентная СН
     */
    public static $terminalTaxation = null;

    /**
     * Налоговая ставка
     * none - без НДС
     * vat0 - НДС по ставке 0%
     * vat5 - НДС по ставке 5%
     * vat7 - НДС по ставке 7%
     * vat10 - НДС по ставке 10%
     * vat22 - НДС по ставке 22%
     * vat105 - НДС чека по расчетной ставке 5/105
     * vat107 - НДС чека по расчетной ставке 7/107
     * vat110 - НДС чека по расчетной ставке 10/110
     * vat122 - НДС чека по расчетной ставке 22/122
     */
    public static $terminalTaxRate = null;



    public function __construct() {}





    public static function setTerminalTaxation($taxation)
    {
        self::$terminalTaxation = $taxation;
    }
    public static function setTerminalTaxRate($taxRate)
    {
        self::$terminalTaxRate = $taxRate;
    }



    public static function setTerminalKey($terminalKey)
    {
        self::$terminalKey = $terminalKey;
    }
    public static function setTerminalPassword($password)
    {
        self::$terminalPassword = $password;
    }





    public static function updatePaymentState($payment_id)
    {

        $payment = TPayments::findOne([
            TPaymentsField::_ID => mDB::id($payment_id),

        ]);
        if (!$payment) {
            throw new \Exception("Payment not found");
        }

        $paymentId = TPaymentsField::PAYMENT_ID_GET($payment)
            ?? (TPaymentsField::INIT_RESULT_GET($payment, [])['PaymentId'] ?? null);




        $data = [
            'PaymentId' => $paymentId,
        ];
        $response = self::sendRequest('GetState', $data);

        TPayments::updateOne(
            [
                TPaymentsField::_ID => mDB::id($payment_id)
            ],
            [
                '$set' => [TPaymentsField::STATUS => $response['Status']]
            ]
        );

        // var_dump($response['Status']);
    }



    public static function CustomerCardsRpc()
    {

        return ShmRPC::makeQuery(TCustomerCards::structure())->pipeline(function () {

            Auth::authenticateOrThrow();

            return [
                [
                    '$match' => [
                        TCustomerCardsField::TERMINAL_KEY => self::$terminalKey,
                        TCustomerCardsField::OWNER => Auth::getAuthID(),
                        TCustomerCardsField::OWNER_COLLECTION => Auth::getAuthCollection()
                    ]
                ]
            ];
        });
    }



    public static function updateCardsByPayment($payment_id)
    {

        $payment = TPayments::findOne([
            TPaymentsField::_ID => mDB::id($payment_id),
        ]);

        if (! $payment) {
            return;
        }

        $CustomerKey = TPaymentsField::INIT_REQUEST_GET($payment, [])['CustomerKey'] ?? null;

        if (! $CustomerKey) {
            return;
        }

        $response = self::sendRequest('GetCardList', [
            "CustomerKey" => $CustomerKey,
        ]);

        $cards = $response ?? [];

        foreach ($cards as $card) {

            TCustomerCards::updateOne(
                [
                    TCustomerCardsField::CARD_ID => $card['CardId'],
                    'deleted_at' => ['$exists' => false],
                    TCustomerCardsField::OWNER => TPaymentsField::OWNER_GET($payment),
                    TCustomerCardsField::OWNER_COLLECTION => TPaymentsField::OWNER_COLLECTION_GET($payment),
                    TCustomerCardsField::TERMINAL_KEY => self::$terminalKey,

                ],
                [

                    '$set' => [
                        ...$card,
                        TCustomerCardsField::TERMINAL_KEY => self::$terminalKey,
                        TCustomerCardsField::OWNER => TPaymentsField::OWNER_GET($payment),
                        TCustomerCardsField::OWNER_COLLECTION => TPaymentsField::OWNER_COLLECTION_GET($payment),
                    ]

                ],
                [
                    'upsert' => true,
                ]
            );
        }
    }








    protected static function generateToken(array $params)
    {
        foreach (['SHOPS', 'RECEIPT', 'DATA'] as $ignore_key) {
            if (isset($params[$ignore_key])) {
                unset($params[$ignore_key]);
            }
        }

        $params['Password'] = self::$terminalPassword;
        ksort($params);

        $token = '';
        foreach ($params as $param_value) {
            if (is_scalar($param_value)) {
                $token .= $param_value;
            }
        }

        return hash('sha256', $token);
    }

    public  static function sendRequest($method, $data)
    {


        $data['TerminalKey'] = self::$terminalKey;


        $data['Token'] = self::generateToken($data);
        $url = self::API_ENDPOINT . $method;




        $headers = [
            'Content-Type' => 'application/json',
        ];


        $client = new Client(self::$default_http_client_options);




        $request = new Request('POST', $url, $headers, json_encode($data));
        $response = $client->sendAsync($request)->wait();


        $body = json_decode($response->getBody(), true);



        return $body;
    }


    public static function routesInit()
    {


        Cmd::command("tbankWorker", function () {


            //Проверка операций которые надо отменить 
            $operation = TPayments::findOne([
                TPaymentsField::STATUS => 'CONFIRMED',
                TPaymentsField::AUTO_REFUNDED => true,
                TPaymentsField::CANCEL_RESULT => ['$exists' => false],
            ]);




            if ($operation) {


                $paymentId = TPaymentsField::PAYMENT_ID_GET($operation);



                if ($paymentId) {
                    TBankCancel::create($paymentId)->request();
                }
            }
        })->everyMinute();


        $f3 = \Base::instance();
        $f3->route('POST|GET ' . self::WEBHOOK_URL, function ($f3) {

            $data = ShmUtils::allRequest();

            $OrderId = $data['OrderId'] ?? null;

            if ($OrderId) {

                $payment = TPayments::findOne([
                    TPaymentsField::ORDER_ID => $OrderId
                ]);

                if ($payment) {

                    /**Requirements: <= 1 characters, [Y]
                     * Признак родительского CC-платежа. 
                     * Обязателен для проведения операции с сохранением реквизитов карты покупателя.
                     * Если передается и установлен в Y, при платеже будут сохранены реквизиты карты 
                     * покупателя. В этом случае после оплаты в уведомлении на AUTHORIZED 
                     * будет передан параметр RebillId для использования 
                     * в методе Провести платеж по сохраненным реквизитам. Для привязки и одновременной оплаты по CБП передавайте Y.*/


                    $dataStatus = $data['Status'] ?? null;
                    $dataRebillId = $data['RebillId'] ?? null;

                    if ($dataStatus == 'AUTHORIZED' && $dataRebillId) {

                        TBankPayment::updateCardsByPayment(TPaymentsField::_ID_GET($payment));
                    }


                    TPayments::updateOne([
                        TPaymentsField::_ID => TPaymentsField::_ID_GET($payment)
                    ], [
                        '$push' => [
                            TPaymentsField::NOTIFICATIONS => $data
                        ]
                    ]);

                    TBankPayment::updatePaymentState(TPaymentsField::_ID_GET($payment));
                }
            }
        });

        $f3->route('GET /payment/status/success', function ($f3) {
            ShmTwig::html('@shm/payment/payment_success.twig');
        });
        $f3->route('GET /payment/status/error', function ($f3) {
            ShmTwig::html('@shm/payment/payment_error.twig');
        });
    }
}
