<?php

namespace Payment\Lib;

use Dever;

class Payfort extends Core
{
    private $config = array();
    private $language = 'en';
    private $url = 'https://checkout.payfort.com/FortAPI/paymentPage';
    private $gatewayUrl = 'https://paymentservices.payfort.com/FortAPI/paymentApi';

    public function __construct($name, $config)
    {
        $this->name = $name;
        $this->config = $config;
    }

    private function getType($type, $currency = '')
    {
        if ($type < 5 && $currency == 'SAR') {
            $type = 4;
        }
        $name = $value = $method = $command = '';
        switch ($type) {
            case 1:
                # 目前不支持
                $name = 'Pay with credit cards (Redirection)';
                $method = 'redirection';
                $currency = '';
                $command = 'PURCHASE';
                break;

            case 2:
                $name = 'Pay with installments (Redirection)';
                $method = 'redirection';
                $currency = 'USD';
                $command = 'PURCHASE';
                break;

            case 3:
                $name = 'Pay with NAPS';
                $value = 'NAPS';
                $currency = 'NAPS';
                $command = 'AUTHORIZATION';
                $method = 'redirection';
                break;

            case 4:
                $name = 'Pay with SADAD';
                $value = 'SADAD';
                $currency = 'SAR';
                $method = 'redirection';
                $command = 'AUTHORIZATION';
                break;

            case 11:
                $name = 'Pay with credit cards (Merchant Page)';
                $method = 'page';
                $currency = '';
                $command = 'TOKENIZATION';
                break;

            case 12:
                $name = 'Pay with installments (Merchant Page)';
                $method = 'page';
                $currency = '';
                $command = 'TOKENIZATION';

                break;

            case 21:
                $name = 'Pay with credit cards (Merchant Page 2.0)';
                $method = 'page_v2';
                $currency = '';
                $command = 'TOKENIZATION';
                break;

        }

        $currency = strtoupper($currency);
        return array
        (
            'id' => $type,
            'name' => $name,
            'value' => $value,
            'method' => $method,
            'currency' => $currency,
            'command' => $command,
        );
    }

    /**
     * 获取统一下单的基本信息
     */
    public function request($type, $uid, $account, $product_name, $amount, $currency, $data = array())
    {
        if (!$data) {
            $data = array();
        }
        $type = $this->getType($type, $currency);
        $order_id = $this->createOrder($uid, $this->name, $product_name, $amount, $type['currency'], $type['id'], $type['name']);

        $method = $type['method'];

        $param = array();
        if ($type['id'] == 3) {
            $param['order_description'] = $product_name;
        }
        $param = $this->param($order_id, $amount, $type['currency'], $type['command'], $type['value'], $type['id'], $param);

        $data += $param;

        return $this->result($method, $param, $data);
    }

    /**
     * 生成基本参数
     *
     * @return mixed
     */
    private function param($order_id, $amount, $currency, $command, $payment_option, $type, $param = array())
    {
        if ($type == 2 || $type == 12) {
            $param['installments'] = 'STANDALONE';
        }

        if ($type == 12 && isset($param['plan_code'])) {
            $param['installments']   = 'YES';
            $command                 = 'PURCHASE';
        }

        if ($currency) {
            $param['amount'] = $this->convertFortAmount($amount, $currency);
            $param['currency'] = $currency;
        }

        $param['access_code'] = $this->config['access_code'];
        $param['merchant_identifier'] = $this->config['merchant_id'];
        $param['merchant_reference'] = $order_id;
        $param['language'] = $this->language;
        if ($payment_option) {
            $param['payment_option'] = $payment_option;
        }
        # AUTHORIZATION（授权）、PURCHASE（购买） TOKENIZATION CHECK_STATUS
        if ($command == 'TOKENIZATION') {
            $param['service_command'] = $command;
        } else {
            $param['command'] = $command;
        }
        
        $param['return_url'] = Dever::url('api.notify?order_id=' . $order_id, 'payment');
        $param['signature'] = $this->signature($this->config['request_phrase'], $param);

        return $param;
    }

    /**
     * 获取返回数据
     *
     * @return mixed
     */
    private function result($method, $param, $data)
    {
        $form = $this->form($param);
        return array('form' => $form, 'url' => $this->url, 'param' => $data, 'method' => $method);
    }

    /**
     * 通知回调
     *
     * @return mixed
     */
    public function notify($param)
    {
        if (empty($param)) {
            return $this->out('invalid_parameters');
        }
        if (!isset($param['signature'])) {
            return $this->out('invalid_parameters');
        }

        $post                   = $param;
        $responseSignature      = $param['signature'];
        $order_id               = $param['merchant_reference'];
        unset($param['l']);
        if (isset($param['3ds'])) {
            unset($param['3ds']);
        }
        if (isset($param['product_name'])) {
            unset($param['product_name']);
        }
        if (isset($param['integration_type'])) {
            unset($param['integration_type']);
        }
        if (isset($param['signature'])) {
            unset($param['signature']);
        }
        if (isset($param['order_id'])) {
            unset($param['order_id']);
        }
        if (isset($param['type'])) {
            unset($param['type']);
        }

        if (isset($param['currency']) && $param['currency']) {
            $param['amount'] = $this->convertFortAmount($param['amount'], $param['currency']);
        }
        
        $amount = $param['amount'];
        if (isset($param['card_number']) && $param['card_number']) {
            unset($param['amount']);
        }

        $signature = $this->signature($this->config['response_phrase'], $param);

        if ($signature != $responseSignature) {
            return $this->updateOrder($param['merchant_reference'], $amount, 'invalid_signature');
        }
        
        if (substr($param['response_code'], 2) != '000') {
            return $this->updateOrder($param['merchant_reference'], $amount, $param['response_message']);
        }

        if (isset($param['card_number']) && $param['card_number']) {
            return $this->pageNotify($post);
        }

        return $this->out('ok');
    }

    /**
     * merchantPageNotifyFort
     *
     * @return mixed
     */
    private function pageNotify($param)
    {
        $type = $this->getType($param['type']);
        $method = $type['method'];
        $post = array();

        $post['customer_ip'] = $_SERVER['REMOTE_ADDR'];
        if (isset($param['token_name'])) {
            $post['token_name'] = $param['token_name'];
        }

        if(isset($param['3ds']) && $param['3ds'] == 'no') {
            $post['check_3ds'] = 'NO';
        }

        if (!$type['currency']) {
            $type['currency'] = 'USD';
        }

        $type['command'] = 'AUTHORIZATION';

        $post = $this->param($param['order_id'], $param['amount'], $type['currency'], $type['command'], $type['value'], $type['id'], $post);
        print_r($post);die;

        $result = Dever::curl($this->gatewayUrl, $post, 'post');

        return $this->notify($result);
    }

    public function form($data)
    {
        $form = '<form style="display:none" name="sg-form" id="sg-form" method="post" action="' . $this->url . '">';
        foreach ($data as $k => $v) {
            $form .= '<input type="hidden" name="' . $k . '" value="' . $v . '">';
        }
        $form .= '<input type="submit" id="submit">';
        return $form;
    }

    /**
     * signature
     *
     * @return mixed
     */
    private function signature($phrase, $request)
    {
        ksort($request);

        $signature_string = '';
        foreach ($request as $k => $v) {
            $signature_string .= $k . '=' . $v;
        }
        $signature_string = $phrase . $signature_string . $phrase;
        return hash('sha256', $signature_string);
    }

    /**
     * Convert Amount with dicemal points
     * @param decimal $amount
     * @param string  $currencyCode
     * @return decimal
     */
    private function convertFortAmount($amount, $currencyCode)
    {
        $new_amount = 0;
        $total = $amount;
        $decimalPoints    = $this->getCurrencyDecimalPoints($currencyCode);
        $new_amount = round($total, $decimalPoints) * (pow(10, $decimalPoints));
        return $new_amount;
    }

    private  function castAmountFromFort($amount, $currencyCode)
    {
        $decimalPoints    = $this->getCurrencyDecimalPoints($currencyCode);
        //return $amount / (pow(10, $decimalPoints));
        $new_amount = round($amount, $decimalPoints) / (pow(10, $decimalPoints));
        return $new_amount;
    }

    private function getCurrencyDecimalPoints($currency)
    {
        $decimalPoint  = 2;
        $arrCurrencies = array(
            'JOD' => 3,
            'KWD' => 3,
            'OMR' => 3,
            'TND' => 3,
            'BHD' => 3,
            'LYD' => 3,
            'IQD' => 3,
            'USD' => 0,
        );
        if (isset($arrCurrencies[$currency])) {
            $decimalPoint = $arrCurrencies[$currency];
        }
        return $decimalPoint;
    }
}
