<?php
namespace common\pay;

use backend\models\RemitLog;
use backend\models\RemitOrder;
use yii\base\Model;

class RemitForm extends Model
{
    /**
     * @var string 通知地址
     */
    public $notifyUrl;
    /**
     * @var int 打款单号
     */
    public $remitNo;
    /**
     * @var string 打款密码
     */
    public $password;
    /**
     * @var int 操作人id
     */
    public $adminId;
    /**
     * @var string 操作人名字
     */
    public $adminName;
    /**
     * @var string 操作人ip
     */
    public $adminIp;
    /**
     * @var string 异步通知响应结果
     */
    private $_outNotifyResult;

    /**
     * @return array
     */
    public function rules()
    {
        return [
            [['notifyUrl', 'remitNo', 'password'], 'required'],
            [['remitNo'], 'integer'],
            [['notifyUrl', 'password', 'adminId', 'adminName', 'adminIp'], 'string'],
        ];
    }

    /**
     * @return bool
     */
    public function outRemit()
    {
        if ($this->validate()) {
            $remitOrder = RemitOrder::find()->where(['remit_no' => $this->remitNo])->limit(1)->asArray()->one();
            if ($remitOrder == null) {
                $this->addError('remitNo', '打款单不存在');
                return false;
            }
            if ($remitOrder['audit_status'] != RemitOrder::STATUS_REAUDIT_SUCCESS) {
                // 复审未通过
                $this->addError('remitNo', '复审未通过');
                return false;
            }
            if ($remitOrder['pay_status'] != RemitOrder::STATUS_PAY_INIT) {
                $this->addError('remitNo', '打款单状态必须是未打款');
                return false;
            }
            $handler = BaseRemitHandler::getRemitHandlerByPayType($remitOrder['pay_type']);
            if ($handler == null) {
                $this->addError('remitNo', '打款通道不存在');
                return false;
            }
            // 待打款 -> 内部打款中
            $saveData = [
                'pay_status' => RemitOrder::STATUS_PAY_INNER_PROCESS,
                'pay_time' => time(),
            ];
            $saveWhere = [
                'id' => $remitOrder['id'],
                'remit_no' => $remitOrder['remit_no'],
                'pay_status' => RemitOrder::STATUS_PAY_INIT,
            ];
            $logData = [];
            $logData['admin_id'] = $this->adminId;
            $logData['admin_name'] = $this->adminName;
            $logData['admin_ip'] = $this->adminIp;
            $transaction = RemitOrder::getDb()->beginTransaction();
            try {
                $affectRows = RemitOrder::updateAll($saveData, $saveWhere);
                if ($affectRows == 0) {
                    throw new \Exception("打款单状态更新失败1,remitNo: " . $remitOrder['remit_no']);
                }
                $logData['memo'] = "打款单状态: 未打款 -> 内部打款中";
                RemitLog::addLog($remitOrder, $logData);
                $transaction->commit();
            } catch (\Exception $e) {
                $transaction->rollBack();
                $logData['memo'] = $e->getMessage();
                RemitLog::addLog($remitOrder, $logData);
                $this->addError('remitNo', $e->getMessage());
                return false;
            }
            // 内部打款中 -> 外部打款中
            $handler->notifyUrl = $this->notifyUrl;
            $params = [];
            $params['ip'] = $this->adminIp;
            $params['password'] = $this->password;
            $isSuccess = false;
//            for ($i = 0; $i < 2; $i++) {
                $result = $handler->outRemit($remitOrder, $params);
                $saveData = [];
                foreach (['pay_status', 'out_no', 'out_no_crc32', 'ret_code', 'res_code', 'ret_msg'] as $field) {
                    isset($result[$field]) && $saveData[$field] = trim($result[$field]);
                }
                unset($result);
                $logData = [];
                $logData['admin_id'] = 0;
                $logData['admin_name'] = '系统';
                $logData['admin_ip'] = '';
                $transaction = RemitOrder::getDb()->beginTransaction();
                try {
                    if (isset($saveData['pay_status']) && $saveData['pay_status'] == RemitOrder::STATUS_PAY_OUTER_PROCESS) {
                        $isSuccess = true;
                        $logData['memo'] = '打款单打款状态：内部打款中 -> 外部打款中';
                    } else {
                        unset($saveData['pay_status']); // 不更新状态
                        $retMsg = '';
                        if (isset($saveData['ret_code'])) {
                            $retMsg .= trim($saveData['ret_code']) . ' ';
                        }
                        if (isset($saveData['res_code'])) {
                            $retMsg .= trim($saveData['res_code']) . ' ';
                        }
                        if (isset($saveData['ret_msg'])) {
                            $retMsg .= trim($saveData['ret_msg']) . ' ';
                        }
                        $logData['memo'] = '外部打款异常：' . trim($retMsg);
                    }
                    $affectRows = RemitOrder::updateAll($saveData, ['remit_no' => $remitOrder['remit_no'], 'pay_status' => [RemitOrder::STATUS_PAY_INNER_PROCESS, RemitOrder::STATUS_PAY_EXCEPTION]]);
                    if ($affectRows == 0) {
                        throw new \Exception("打款单状态更新失败2,remitNo: {$remitOrder['remit_no']}");
                    }
                    RemitLog::addLog($remitOrder, $logData);
                    $transaction->commit();
                } catch (\Exception $e) {
                    $transaction->rollBack();
                    $logData['memo'] = $e->getMessage();
                    RemitLog::addLog($remitOrder, $logData);
                }
//                if ($isSuccess) {
//                    break;
//                }
//                usleep(100000); // 休眠100ms 重试
//            }
            if ($isSuccess == false) {
                $this->addError('remitNo', '打款失败');
            }
        }
        return !$this->hasErrors();
    }

    /**
     * @param array $data
     * @return bool
     */
    public function handleNotify($data)
    {
        if (!isset($data['remitNo']) || trim($data['remitNo']) == '') {
            return false;
        }
        $remitOrder = RemitOrder::findByRemitNo($data['remitNo']);
        if ($remitOrder == null) {
            return false;
        }
        unset($data['token']);
        unset($data['remitNo']);
        $handler = BaseRemitHandler::getRemitHandlerByPayType($remitOrder['pay_type']);
        $success = false;
        if ($handler != null) {
            $success = $handler->handleNotify($data);
            $this->_outNotifyResult = $handler->outNotify($success);
        }
        return $success;
    }

    /**
     * @return string
     */
    public function getOutNotifyResult()
    {
        return $this->_outNotifyResult;
    }
}
