<?php

namespace Modules\Mall\Models\Traits;

use Encore\Admin\Facades\Admin;
use Exception;
use Illuminate\Support\Facades\DB;
use Modules\Mall\Events\RefundAgreed;
use Modules\Mall\Events\RefundCompleted;
use Modules\Mall\Events\RefundRefused;
use Modules\Payment\Models\Payment;

trait RefundActions
{

    public $operator;

    /**
     * Notes: 设置操作人
     *
     * @Author: 玄尘
     * @Date  : 2021/5/17 16:12
     * @param $operator
     * @return $this
     */
    public function setOperator($operator)
    {
        $this->operator = $operator;

        return $this;
    }

    /**
     * Notes: 设置备注
     *
     * @Author: 玄尘
     * @Date  : 2021/5/17 16:12
     * @param $remark
     * @return $this
     */
    public function setRemark($remark)
    {
        $this->remark = $remark;

        return $this;
    }

    /**
     * Notes: 同意退款
     *
     * @Author: 玄尘
     * @Date  : 2021/5/17 11:59
     * @param $remark
     * @return bool
     * @throws \Exception
     */
    public function agree($remark = null): bool
    {
        if (! $this->can('agree')) {
            throw new Exception("退款单状态不可以同意退款");
        }

        DB::transaction(function () use ($remark) {
            $this->actual_total = $this->refund_total;
            $this->save();

            $this->apply('agree');
            $this->setOrderApply($this->order, 'agree');

            if ($this->order->express) {
                $this->express()->create();
            }

            $this->setLogs($remark);

            //订单已经进入发货流程，需要客户退货
            if ($this->order->express && $this->order->express->deliver_at) {
                $this->apply('deliver');
                $this->setOrderApply($this->order, 'user_deliver');
            } else {
                //未发货设置为退款中
                $this->apply('process');
                $this->setOrderApply($this->order, 'process');
            }

            event(new RefundAgreed($this));
        });

        return true;
    }

    /**
     * Notes: 拒绝退款
     *
     * @Author: 玄尘
     * @Date  : 2021/5/17 12:01
     * @param  string|null  $remark
     * @return bool
     * @throws \Exception
     */
    public function refuse(string $remark = null): bool
    {
        if (! $this->can('refuse')) {
            throw new Exception("退款单状态不可以拒绝退款");
        }

        DB::transaction(function () use ($remark) {

            $this->apply('refuse');
            $this->setOrderApply($this->order, 'refuse');

            $this->setLogs($remark);

            event(new RefundRefused($this));
        });

        return true;
    }

    /**
     * Notes: 退货退款中
     *
     * @Author: 玄尘
     * @Date  : 2021/5/17 14:29
     * @param          $company
     * @param  string  $number
     * @return bool
     * @throws \Exception
     */
    public function deliver($company, string $number): bool
    {
        if ($this->can('delivered')) {
            DB::transaction(function () use ($company, $number) {
                $this->express()->update([
                    'company'    => $company,
                    'number'     => $number,
                    'deliver_at' => now(),
                ]);

                // 修改状态机
                $this->apply('delivered');
                $this->setOrderApply($this->order, 'user_deliverd');

                $this->setLogs('客户退货');

            });

            return true;
        } else {
            throw new Exception('订单状态不可发货');
        }

    }

    /**
     * Notes: 确认收货
     *
     * @Author: 玄尘
     * @Date  : 2021/5/17 14:30
     * @return bool
     * @throws \Exception
     */
    public function receive(): bool
    {
        if (! $this->can('sign')) {
            throw new Exception('退款单状态不可以确认收货');
        }

        $this->express->receive_at = now();
        $this->express->save();

        $this->apply('sign');
        //设置为退款中
        $this->apply('process');
        $this->setOrderApply($this->order, 'process');

        $this->setLogs('店家签收');

        return true;
    }

    /**
     * Notes: 标记退款完成
     *
     * @Author: 玄尘
     * @Date  : 2021/5/17 14:32
     * @return bool
     * @throws \Exception
     */
    public function complete(): bool
    {
        if (! $this->can('completed')) {
            throw new Exception("订单状态不对，不可设置完成");
        }

        DB::transaction(function () {
            $this->apply('completed');
            //设置时间
            $this->refunded_at = now();
            $this->save();

            $this->setLogs('订单标记完成');

            event(new RefundCompleted($this));
        });

        return true;
    }

    /**
     * Notes: 退款
     *
     * @Author: 玄尘
     * @Date  : 2021/5/17 14:52
     * @throws \Exception
     */
    public function returns(): bool
    {
        try {
            $payment = $this->order->payment;
            if (! $payment) {
                throw new Exception("退款失败，未找到支付信息");
            }
            //微信支付
            if ($payment->driver == Payment::DRIVER_WECHAT) {
                $order  = [
                    'out_trade_no'  => $payment->trade_id,
                    'out_refund_no' => $this->refund_no,
                    'total_fee'     => $payment->total * 100,
                    'refund_fee'    => $this->actual_total * 100,
                ];
                $result = app('pay.wechat')->refund($order);

                if ($result->result_code != 'SUCCESS') {
                    throw new Exception("退款失败，".$result->return_msg);
                }

                $this->setLogs('退款完成');

                return true;
            } elseif ($payment->driver == Payment::DRIVER_ALIPAY) {//支付宝支付

                $order = [
                    'out_trade_no'  => $this->order->order_no,
                    'refund_amount' => $this->actual_total,
                ];

                $result = app('pay.alipay')->refund($order);

                if ($result->code != '10000') {
                    throw new Exception("退款失败，".$result->msg);
                }

                return true;
            } elseif ($payment->driver == Payment::DRIVER_SCORE) {//水滴支付

                $this->user->account->rule('score_buy_refund', $this->actual_total, false, [
                    'order_no'  => $this->order->order_no,
                    'refund_no' => $this->refund_no,
                ]);

                return true;
            } else {
                throw new Exception("退款失败，未找到支付路径");
            }
        } catch (Exception $exception) {
            throw new Exception($exception->getMessage());
        }

    }

    /**
     * Notes: 记录日志
     *
     * @Author: 玄尘
     * @Date  : 2021/5/17 16:03
     * @param  null  $remark
     * @param  null  $title
     * @param  null  $pictures
     */
    public function setLogs($remark = null, $title = null, $pictures = null)
    {
        if (empty($this->operator)) {
            $this->operator = $this->user;
        }

        if (empty($this->operator)) {
            $this->operator = Admin::user();
        }

        $refund = $this->refresh();
        $logs   = [
            'userable_type' => get_class($this->operator),
            'userable_id'   => $this->operator->id,
            'remark'        => $remark,
            'title'         => $title,
            'pictures'      => $pictures,
            'state'         => $refund->state,
        ];

        $refund->logs()->create($logs);
    }

    /**
     * Notes: 修改订单状态机
     *
     * @Author: 玄尘
     * @Date  : 2021/6/17 9:22
     */
    public function setOrderApply($order, $status)
    {
        //如果都已经退款/货
        if ($order->refund_items_count == $order->items()->count()) {
            $order->apply($status);
        }
    }

}
