<?php
namespace Sale\Handlers\PaySystem;

use Bitrix\Main;
use Bitrix\Main\Error;
use Bitrix\Main\Request;
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\Type\DateTime;
use Bitrix\Sale\Payment;
use Bitrix\Sale\PaySystem;
use Bitrix\Sale\PaySystem\ServiceResult;

class gateline_paymentHandler extends PaySystem\ServiceHandler
{
    private $payment = null;

    public function getCurrencyList()
    {
        return ['RUB'];
    }

    protected function getUrlList()
    {
        return [
            'pay' => [
                self::TEST_URL => 'https://simpleapi.sandbox.gateline.net:18610/pay',
                self::ACTIVE_URL => 'https://simpleapi.gateline.ru/pay',
            ],
        ];
    }

    protected function isTestMode(Payment $payment = null)
    {
        return ($this->option('sandbox') == 'Y');
    }

    public static function getIndicativeFields()
    {
        return ['merchant_order_id', 'code', 'status', 'message', 'checksum'];
    }

    public function getPaymentIdFromRequest(Request $request)
    {
        return intval($request->get('merchant_order_id'));
    }

    private function makeParam($param, $diff)
    {
        return strval(trim($this->option($param)) + $diff);
    }

    private function generateReceipt($order_id, $email, $merchant_order_id)
    {
        $positions = array();
        $payments = array();
    
        $db_basket = \CSaleBasket::GetList(array('ID' => 'ASC'), array("ORDER_ID"=>$order_id));
        while ($arBasket = $db_basket->GetNext())
        {
            array_push($positions, 
            [
                'Quantity'              => $arBasket['QUANTITY'],
                'Text'                  => $arBasket['NAME'],
                'Price'                 => $arBasket['PRICE'],
                'PaymentMethodType'     => $this->makeParam('paymentmethodtype', -100),
                'PaymentSubjectType'    => $this->makeParam('paymentsubjecttype', -100),
                'Tax'                   => $this->makeParam('tax', -100),
            ]);
            
            array_push($payments, 
            [
                'Type'      => $this->makeParam('paymenttype', -100),
                'Amount'    => $arBasket['QUANTITY'] * $arBasket['PRICE']
            ]);
        }
    
        $json = array();
 
        array_push($json, ['electronic_receipt' => 
            [
                'Id'        => strval($merchant_order_id),
                'INN'       => trim($this->option('inn')),
                'Group'     => trim($this->option('group')),
                'Content'   => [
                    'Type'              => $this->makeParam('type', -100),
                    'AgentType'         => $this->makeParam('agenttype', -100),
                    'CustomerContact'   => $email,
                    'Positions'         => $positions,
                    'CheckClose'     => [
                        'Payments'          => $payments,
                        'TaxationSystem'    => $this->makeParam('taxationsystem', -100),
                    ]
                ]
            ]
        ]);
       
        return json_encode($json[0]);
    }

    public function initiatePay(Payment $payment, Request $request = null)
    {
        $this->payment = $payment;
        
        $params = [
            'site' => trim($this->option('uid')),
            'merchant_order_id' => $payment->getId(),
            'amount' =>  number_format($payment->getSum(), 2, '.', ''),
            'description' => 'Payment #'.$payment->getId(),
            'email' => $this->email(),
        ];
        if ($this->option('fiscalization') == 'Y') {
            $params['extended'] = $this->generateReceipt($payment->getId(), $this->email(), $payment->getId());
        }

        $params['checksum'] = $this->calc_checksum($params);
        $params['url'] = $this->getUrl($payment, 'pay');

        $this->setExtraParams($params);
        return $this->showTemplate($payment, 'template');
    }

    public function processRequest(Payment $payment, Request $request)
    {
        $this->payment = $payment;

        $params = $request->toArray();

        if (!$this->is_checksum_valid($params)) {
            return $this->result_error('GATELINE_ERROR_CHECKSUM');
        }
        if ($payment->isPaid()) {
            return $this->result_error('GATELINE_ERROR_ALREADY_PAID');
        }
        if ($params['status'] == 'success') {
            return $this->result_success($params);
        }
        if ($params['status'] == 'failed') {
            return $this->result_fail($params);
        }

        return $this->result_error('GATELINE_ERROR');
    }

    private function result_error($type)
    {
        $msg = Loc::getMessage($type);

        $result = new PaySystem\ServiceResult();
        $result->addError(new Main\Error($msg));

        $this->redirect(\COption::GetOptionString('sale', 'sale_ps_fail_path', '/'));

        return $result;
    }

    private function result_success($params)
    {
        $params['is_success'] = 'Y';
        return $this->result_final($params);
    }

    private function result_fail($params)
    {
        $params['is_success'] = 'N';
        return $this->result_final($params);
    }

    private function result_final($params)
    {
        $fields = [
            'PS_STATUS' => $params['is_success'],
            'PS_STATUS_CODE' => $params['code'],
            'PS_STATUS_DESCRIPTION' => $params['status'],
            'PS_STATUS_MESSAGE' => $params['message'],
            'PS_RESPONSE_DATE' => new DateTime(),
        ];

        $result = new PaySystem\ServiceResult();
        $result->setPsData($fields);

        if ($params['is_success'] == 'Y') {
            $result->setOperationType(PaySystem\ServiceResult::MONEY_COMING);
            $this->redirect(\COption::GetOptionString('sale', 'sale_ps_success_path', '/'));
        }
        else {
            $this->redirect(\COption::GetOptionString('sale', 'sale_ps_fail_path', '/'));
        }

        return $result;
    }

    private function option($name)
    {
        return $this->getBusinessValue($this->payment, 'GATELINE_'.strtoupper($name));
    }

    private function redirect($location)
    {
        echo '<script>window.location="'.$location.'"</script>';
    }

    private function email()
    {
        $order = $this->payment->getCollection()->getOrder();
        $properties = $order->getPropertyCollection();
        if ($properties->getUserEmail()) {
            return $properties->getUserEmail()->getValue();
        }
        return '';
    }

    private function calc_checksum($query)
    {
        unset($query['checksum']);
        ksort($query);

        $kv = [];
        foreach ($query as $key => $value) {
            $kv[] = $key . '=' . $value;
        }
        $content = implode(';', $kv);

        return hash_hmac('sha1', $content, trim($this->option('passwd')));
    }

    private function is_checksum_valid($request)
    {
        $sum = $request['checksum'];
        return ($this->calc_checksum($request) == $sum);
    }
}
