<?php

namespace Modules\Mall\Facades;

use Exception;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Facades\DB;
use Modules\Mall\Events\RefundApplied;
use Modules\Mall\Models\Order as OrderModel;
use Modules\Mall\Models\Refund as RefundModel;

class Refund
{

    protected $user;

    /**
     * @var string
     */
    protected string $remark;

    /**
     * @var array
     */
    protected array $logs;

    protected $refund;

    protected $order;

    protected $items;

    protected $total;

    /**
     * @throws \Exception
     */
    public function user($user): Refund
    {
        if ($user instanceof Authenticatable) {
            $this->user = $user;
        } else {
            throw new Exception('非法用户');
        }

        return $this;
    }

    /**
     * Notes: 订单
     *
     * @Author: 玄尘
     * @Date  : 2021/5/17 8:46
     * @param  OrderModel  $order
     * @return $this
     */
    public function order(OrderModel $order): Refund
    {
        $this->order = $order;

        return $this;
    }

    /**
     * Notes:商品
     *
     * @Author: 玄尘
     * @Date  : 2021/5/17 8:46
     * @param  array  $items
     * @return Refund
     */
    public function items(array $items): Refund
    {
        $this->items = $items;

        return $this;
    }

    /**
     * Notes: 退款金额
     *
     * @Author: 玄尘
     * @Date  : 2021/5/17 8:48
     * @param  float  $total
     * @return Refund
     */
    public function total(float $total): Refund
    {
        $this->total = $total;

        return $this;
    }

    /**
     * Notes: 设置订单备注信息
     *
     * @Author: 玄尘
     * @Date  : 2021/5/21 10:31
     * @param  string  $remark
     * @return $this
     */
    public function remark(string $remark): Refund
    {
        $this->remark = $remark;

        return $this;
    }

    /**
     * Notes: 退款日志
     *
     * @Author: 玄尘
     * @Date  : 2021/5/17 11:37
     * @param $logs
     * @return $this
     */
    public function logs($logs): Refund
    {
        if (! isset($logs['remark']) && ! empty($this->remark)) {
            $logs['remark'] = $this->remark;
        }

        $this->logs = $logs;

        return $this;
    }

    /**
     * Notes: 设置退款商品
     *
     * @Author: 玄尘
     * @Date  : 2021/5/17 8:51
     */
    public function setItems(): Refund
    {
        $this->items = $this->order->items->map(function ($item) {
            return [
                'order_item_id' => $item->id,
                'qty'           => $item->qty,
            ];
        });

        return $this;
    }

    /**
     * Notes: 创建退款单
     *
     * @Author: 玄尘
     * @Date  : 2021/5/17 8:49
     * @return mixed
     * @throws \Exception
     */
    public function create()
    {

        if (! $this->order) {
            throw new Exception('未设置订单');
        }

        if (empty($this->items)) {
            $this->setItems();
        }

        if (! $this->order->can('refund')) {
            throw new Exception('订单状态不可退款');
        }

        $maxAmount   = 0;
        $refundItems = [];

        //判断最大可退数量
        foreach ($this->items as $item) {

            $orderItem = $this->order->items()->find($item['order_item_id']);
            if (! $orderItem) {
                throw new Exception('未找到可退商品');
            }

            if (! $orderItem->canRefund()) {
                throw new \Exception('退款/货失败，此商品不可退款/货');
            }

            if ($item['qty'] <= 0) {
                throw new Exception('【'.$orderItem->source['goods_name'].'】退货数量必须大于0');
            }

            if ($item['qty'] > $orderItem->qty) {
                throw new Exception('【'.$orderItem->source['goods_name'].'】超过最大可退数量');
            }

            $maxAmount += $orderItem->price * $item['qty'];

            $refundItems[] = new RefundItem($orderItem, $item['qty']);
        }

        // 自动计算退款金额
        if (is_null($this->total)) {
            $this->total = $maxAmount;
        } elseif ($this->total > $maxAmount) {
            throw new Exception('超过最大可退金额');
        }

        DB::transaction(function () use ($refundItems) {
            $this->refund = $this->order->refunds()
                ->create([
                    'refund_total' => $this->total,
                    'actual_total' => 0,
                    'user_id'      => $this->user->id,
                    'shop_id'      => $this->order->shop_id,
                    'state'        => RefundModel::REFUND_APPLY,
                    'remark'       => $this->remark,
                ]);

            foreach ($refundItems as $item) {
                $this->refund->items()->create($item->toArray());
            }

            if ($this->logs) {
                $this->createLog();
            }

            event(new RefundApplied($this->order, $this->refund));

        });

        return $this->refund;

    }

    /**
     * Notes: 添加日志
     *
     * @Author: 玄尘
     * @Date  : 2020/12/11 11:43
     */
    public function createLog()
    {
        $logs = $this->logs;

        if ($this->user) {
            $logs['userable_type'] = get_class($this->user);
            $logs['userable_id']   = $this->user->id;
            $logs['state']         = $this->refund->state;
        }

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

}
