<?php

namespace AppBundle\Component\Payment\Alipay;

use AppBundle\Component\Payment\Response;

class AlipayResponse extends Response
{
    protected $url = 'https://mapi.alipay.com/gateway.do';

    public function getPayData()
    {
        $error = $this->hasError();

        if ($error) {
            throw new \RuntimeException(sprintf($this->getServiceKernel()->trans('支付宝支付校验失败(%error%)。', array('%error%' => $error))));
        }

        $params = $this->params;
        if ($params['trade_status'] == 'WAIT_SELLER_SEND_GOODS') {
            $trade_no = $params['trade_no'];
            $result = $this->confirmSellerSendGoods($trade_no);

            if ($result == 'WAIT_BUYER_CONFIRM_GOODS') {
                return array('sn' => $params['trade_no'], 'status' => 'waitBuyerConfirmGoods');
            }
        }

        if ($params['trade_status'] == 'WAIT_BUYER_CONFIRM_GOODS') {
            return array('sn' => $params['trade_no'], 'status' => 'waitBuyerConfirmGoods');
        }

        $data = array();
        $data['payment'] = 'alipay';
        $data['sn'] = $params['out_trade_no'];
        if (in_array($params['trade_status'], array('TRADE_SUCCESS'))) {
            $data['status'] = 'success';
        } elseif (in_array($params['trade_status'], array('TRADE_CLOSED'))) {
            $data['status'] = 'closed';
        } elseif (in_array($params['trade_status'], array('WAIT_BUYER_PAY'))) {
            $data['status'] = 'created';
        } else {
            $data['status'] = 'unknown';
        }
        $data['amount'] = $params['total_fee'];

        if (!empty($params['gmt_payment'])) {
            $data['paidTime'] = strtotime($params['gmt_payment']);
        } elseif (!empty($params['notify_time'])) {
            $data['paidTime'] = strtotime($params['notify_time']);
        } else {
            $data['paidTime'] = time();
        }
        $data['raw'] = $params;

        return $data;
    }

    private function hasError()
    {
        $sign = $this->signParams($this->params);

        if ($this->params['sign'] !== $sign) {
            return 'sign_error';
        }
        if (!empty($this->params['notify_id'])) {
            $notifyResult = $this->getRequest('https://mapi.alipay.com/gateway.do', array(
                'notify_id' => $this->params['notify_id'],
                'service' => 'notify_verify',
                'partner' => $this->options['key'],
            ));
            if (strtolower($notifyResult) !== 'true') {
                return 'notify_verify_error';
            }
        }

        return false;
    }

    private function confirmSellerSendGoods($trade_no)
    {
        $params = array();
        $params['service'] = 'send_goods_confirm_by_platform';
        $params['partner'] = $this->options['key'];
        $params['_input_charset'] = 'utf-8';
        $params['sign_type'] = 'MD5';
        $params['trade_no'] = $trade_no;
        $params['transport_type'] = 'DIRECT';
        $params['sign'] = $this->signParams($params);

        $html_text = $this->postRequest($this->url, $params);
        $doc = new \DOMDocument('1.0', 'UTF-8');
        $doc->loadXML($html_text);

        if (!empty($doc->getElementsByTagName('alipay')->item(0)->nodeValue)) {
            $trade_status = $doc->getElementsByTagName('trade_status')->item(0)->nodeValue;

            return $trade_status;
        } else {
            return null;
        }
    }

    private function postRequest($url, $params)
    {
        $curl = curl_init();

        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_USERAGENT, 'Topxia Payment Client 1.0');
        curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
        curl_setopt($curl, CURLOPT_TIMEOUT, 10);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_HEADER, 0);
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
        curl_setopt($curl, CURLOPT_URL, $url);

        curl_setopt($curl, CURLINFO_HEADER_OUT, true);

        $response = curl_exec($curl);

        curl_close($curl);

        return $response;
    }

    private function signParams($params)
    {
        unset($params['sign_type']);
        unset($params['sign']);

        ksort($params);
        $params = array_filter($params);

        $sign = '';
        foreach ($params as $key => $value) {
            $sign .= $key.'='.$value.'&';
        }
        $sign = substr($sign, 0, -1);
        $sign .= $this->options['secret'];

        return md5($sign);
    }
}
