<?php
/**
 * @table paysystems
 * @id cryptonator
 * @title Cryptonator
 * @visible_link https://www.cryptonator.com/merchant/
 * @logo_url cryptonator.png
 * @recurring none
 * @am_payment_api 6.0
 */
class Am_Paysystem_Cryptonator extends Am_Paysystem_Abstract
{
    const PLUGIN_STATUS = self::STATUS_BETA;
    const PLUGIN_REVISION = '6.3.43';

    protected $defaultTitle = 'Cryptonator';
    protected $defaultDescription = 'paid by bitcoins';

    const ENDPOINT = 'https://api.cryptonator.com/api/merchant/v1/';

    protected $_isDebug = true;

    public function supportsCancelPage()
    {
        return true;
    }

    public function getRecurringType()
    {
        return self::REPORTS_NOT_RECURRING;
    }

    public function _initSetupForm(Am_Form_Setup $form)
    {
        $form->addText('merchant_id', ['class' => 'am-el-wide'])
            ->setLabel("Merchant ID\n" .
                'Get it from your Cryptonator account')
            ->addRule('required');

        $form->addSecretText('secret', ['class' => 'am-el-wide'])
            ->setLabel("Secret\n" .
                'Get it from your Cryptonator account')
            ->addRule('required');
    }

    public function isConfigured()
    {
        return $this->getConfig('merchant_id') && $this->getConfig('secret');
    }

    public function getSupportedCurrencies()
    {
        return ['EUR', 'USD', 'RUB'];
    }

    function currency($currency)
    {
        switch ($currency) {
            case "RUB":
                return 'rur';
            default:
                return strtolower($currency);
        }
    }

    function sign($params)
    {
        return sha1(implode('&', $params) . "&{$this->getConfig('secret')}");
    }

    public function _process($invoice, $request, $result)
    {
        $this->_startpayment($invoice, $request, $result);
    }

    function _startpayment($invoice, $request, $result)
    {
        $params = [
            'merchant_id' => $this->getConfig('merchant_id'),
            'item_name' => $invoice->getLineDescription(),
            'order_id' => $invoice->public_id,

            'item_description' => '',

            'invoice_amount' => $invoice->first_total,
            'invoice_currency' => $this->currency($invoice->currency),
            'success_url' => $this->getReturnUrl(),
            'failed_url' => $this->getCancelUrl(),

            'language' => 'en',
        ];

        $a = new Am_Paysystem_Action_Redirect(self::ENDPOINT . 'startpayment?' . http_build_query($params));
        $result->setAction($a);
    }

    function _createinvoice($invoice, $request, $result)
    {
        $req = new Am_HttpRequest(self::ENDPOINT . 'createinvoice', Am_HttpRequest::METHOD_POST);
        $params = [
            'merchant_id' => $this->getConfig('merchant_id'),
            'item_name' => $invoice->getLineDescription(),
            'order_id' => $invoice->public_id,

            'item_description' => '',

            'checkout_currency' => 'bitcoin',
            'invoice_amount' => strval((float)$invoice->first_total), // need to convert 12.00 -> 12, otherwise we get issue with secret_hash mismatch
            'invoice_currency' => $this->currency($invoice->currency),
            'success_url' => $this->getReturnUrl(),
            'failed_url' => $this->getCancelUrl(),

            'language' => '',
        ];
        $params['secret_hash'] = $this->sign($params);
        $req->addPostParameter($params);

        $res = $req->send();
        $this->log($req, $res, 'createinvoice');

        if ($res->getStatus() != 201) {
            throw new Am_Exception_InternalError;
        }

        $data = json_decode($res->getBody(), true);

        if (!isset($data['invoice_id'])) {
            throw new Am_Exception_InternalError;
        }

        $a = new Am_Paysystem_Action_Redirect("https://www.cryptonator.com/merchant/invoice/{$data['invoice_id']}");
        $result->setAction($a);
    }

    public function createTransaction($request, $response, array $invokeArgs)
    {
        return new Am_Paysystem_Transaction_Cryptonator($this, $request, $response, $invokeArgs);
    }

    function getReadme()
    {
        $url = $this->getPluginUrl('ipn');
        return <<<CUT
Set Callback URL in Cryptonator account (Merchant -> Advanced Settings) to:
{$url}
CUT;

    }

    function log($req, $resp, $title)
    {
        if (!$this->_isDebug)
            return;
        $l = $this->getDi()->invoiceLogRecord;
        $l->paysys_id = $this->getId();
        $l->title = $title;
        $l->add($req);
        $l->add($resp);
    }
}

class Am_Paysystem_Transaction_Cryptonator extends Am_Paysystem_Transaction_Incoming
{
    public function getUniqId()
    {
        return $this->request->getParam('date_time');
    }

    public function validateSource()
    {
        $params = $this->request->getRequestOnlyParams();
        $hash = $params['secret_hash'];
        unset($params['secret_hash']);

        return $hash && $hash == $this->getPlugin()->sign($params);
    }

    public function validateStatus()
    {
        return $this->request->getParam('invoice_status') == 'paid';
    }

    public function validateTerms()
    {
        return floatval($this->request->getParam('invoice_amount')) == floatval($this->invoice->first_total)
            && $this->request->getParam('invoice_currency') == $this->plugin->currency($this->invoice->currency);
    }

    public function findInvoiceId()
    {
        return $this->request->getParam('order_id');
    }
}