<?php

namespace Modules\Mall\Models;

use App\Models\Model;
use App\Traits\OrderByIdDesc;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\SoftDeletes;
use Modules\Mall\Models\Traits\BelongsToShop;
use Modules\Mall\Models\Traits\OrderActions;
use Modules\Mall\Models\Traits\OrderCando;
use Modules\Mall\Models\Traits\OrderScopes;
use Modules\Mall\Traits\WithWorkflow;
use Modules\Payment\Traits\WithPayments;
use Modules\User\Traits\BelongsToUser;
use Overtrue\LaravelVersionable\Versionable;

class Order extends Model
{

    use BelongsToUser,
        BelongsToShop,
        OrderByIdDesc,
        OrderCando,
        Versionable,
        WithWorkflow,
        OrderActions,
        WithPayments,
        OrderScopes,
        SoftDeletes;

    protected $table = 'mall_orders';

    protected $dates = [
        'paid_at',
        'expired_at',
    ];

    protected $casts   = [
        'source' => 'json',
    ];
    protected $appends = ['total'];
    /**
     * 不参与版本记录的字段
     *
     * @var array|string[]
     */
    protected array $dontVersionable = ['updated_at'];

    const STATUS_INIT      = 'INIT';             // 订单初始化：用户已下单，未付款
    const STATUS_CANCEL    = 'CANCEL';           // 订单取消：用户未支付并取消订单，超时未支付后自动取消订单
    const STATUS_PAID      = 'PAID';             // 已支付：用户付款完成，等待发货
    const STATUS_DELIVERED = 'DELIVERED';        // 已发货：卖家已发货
    const STATUS_SIGNED    = 'SIGNED';           // 已签收：用户已签收
    const STATUS_COMPLETED = 'COMPLETED';        // 已完成：用户签收N天后，完成订单，不再做任何操作，

    const REFUND_APPLY     = 'REFUND_APPLY';          // 申请退款
    const REFUND_AGREE     = 'REFUND_AGREE';          // 同意退款
    const REFUND_DELIVER   = 'REFUND_DELIVER';        // 等待客户退货
    const REFUND_DELIVERD  = 'REFUND_DELIVERD';       // 客户发货
    const REFUND_REFUSE    = 'REFUND_REFUSE';         // 拒绝退款
    const REFUND_PROCESS   = 'REFUND_PROCESS';        // 退款中
    const REFUND_COMPLETED = 'REFUND_COMPLETED';      // 退款完成

    const STATUS_MAP = [
        self::STATUS_INIT      => '未付款',
        self::STATUS_CANCEL    => '已取消',
        self::STATUS_PAID      => '待发货',
        self::STATUS_DELIVERED => '已发货',
        self::STATUS_SIGNED    => '已签收',
        self::STATUS_COMPLETED => '完成',
        self::REFUND_APPLY     => '申请退款',
        self::REFUND_AGREE     => '同意退款',
        self::REFUND_REFUSE    => '拒绝退款',
        self::REFUND_DELIVER   => '等待退货',
        self::REFUND_DELIVERD  => '客户退货',
        self::REFUND_PROCESS   => '退款中',
        self::REFUND_COMPLETED => '退款完成',
    ];

    const CANCEL_BY_USER   = 2; // 买家取消
    const CANCEL_BY_SELLER = 3; // 卖家取消
    const CANCEL_BY_SYSTEM = 4; // 系统取消

    const TYPE_NORMAL = 1;          // 正常
    const TYPE_SAMPLE = 2;          // 提货
    const TYPE_SCORE  = 3;          // 积分兑换

    const TYPE_MAP = [
        self::TYPE_NORMAL => '正常',
        self::TYPE_SAMPLE => '提货',
        self::TYPE_SCORE  => '积分兑换',
    ];

    const CHANNEL_USER   = 1;
    const CHANNEL_SYSTEM = 2;

    const CHANNEL_MAP = [
        self::CHANNEL_USER   => '会员',
        self::CHANNEL_SYSTEM => '公司',
    ];

    public static function boot()
    {
        parent::boot();

        self::creating(function ($model) {
            $time = explode(' ', microtime());

            $counter = $model->whereDate('created_at', Carbon::today())->count() + 1;

            $len = config('mall.order_no_counter_length');

            $len = $len < 6 ? 6 : $len;
            $len = $len > 16 ? 16 : $len;

            $model->order_no = date('YmdHis').
                sprintf('%06d', $time[0] * 1e6).
                sprintf('%0'.$len.'d', $counter);

            $model->state      = self::STATUS_INIT;
            $model->expired_at = Carbon::now()->addMinutes(10);
        });
    }

    /**
     * 获取该模型的路由的自定义键名
     *
     * @return string
     */
    public function getRouteKeyName(): string
    {
        return 'order_no';
    }

    /**
     * Notes   : 获取订单总额
     *
     * @Date   : 2021/3/16 1:48 下午
     * @Author : < Jason.C >
     * @return float
     */
    public function getTotalAttribute(): float
    {
        if ($this->original) {
            return sprintf("%.2f", $this->original['amount'] + $this->original['freight']);
        }

        return sprintf("%.2f", $this->amount + $this->freight);
    }

    /**
     * Notes   : 订单状态文本
     *
     * @Date   : 2021/5/10 3:24 下午
     * @Author : < Jason.C >
     * @return string
     */
    public function getStateTextAttribute(): string
    {
        return self::STATUS_MAP[$this->state];
    }

    /**
     * Notes: 订单类型
     *
     * @Author: 玄尘
     * @Date: 2022/10/13 16:53
     * @return string
     */
    public function getTypeTextAttribute(): string
    {
        return self::TYPE_MAP[$this->type];

    }

    /**
     * Notes   : 订单发货记录
     *
     * @Date   : 2021/5/11 9:47 上午
     * @Author : < Jason.C >
     * @return HasOne
     */
    public function express(): HasOne
    {
        return $this->hasOne(OrderExpress::class);
    }

    /**
     * Notes   : 订单条目
     *
     * @Date   : 2021/5/11 9:47 上午
     * @Author : < Jason.C >
     * @return HasMany
     */
    public function items(): HasMany
    {
        return $this->hasMany(OrderItem::class);
    }

    /**
     * Notes: 获取商品
     *
     * @Author: 玄尘
     * @Date  : 2021/10/27 15:01
     * @return \Illuminate\Database\Eloquent\HigherOrderBuilderProxy|mixed
     */
    public function getGoodsAttribute()
    {
        return $this->items()->first()->source;
    }

    /**
     * Notes   : 退款单
     *
     * @Date   : 2021/5/11 9:48 上午
     * @Author : < Jason.C >
     * @return HasMany
     */
    public function refunds(): HasMany
    {
        return $this->hasMany(Refund::class);
    }

    /**
     * Notes: 获取退款商品数
     *
     * @Author: 玄尘
     * @Date  : 2021/5/19 9:50
     * @return int
     */
    public function getRefundItemsCountAttribute(): int
    {
        $order_id = $this->id;

        return RefundItem::query()
            ->whereHas('order_item', function ($query) use ($order_id) {
                $query->where('order_id', $order_id);
            })
            ->whereHas('refund', function ($query) {
                $query->whereNotIN('state', [Refund::REFUND_APPLY]);
            })
            ->count();
    }

    /**
     * Notes   : 工作流获取状态
     *
     * @Date   : 2021/5/8 3:52 下午
     * @Author : < Jason.C >
     * @return string
     */
    public function getCurrentState(): string
    {
        return $this->state;
    }

    /**
     * Notes   : 工作流设置状态
     *
     * @Date   : 2021/5/8 4:01 下午
     * @Author : < Jason.C >
     * @param $state
     */
    public function setCurrentState($state)
    {
        $this->state = $state;
        $this->save();
    }

    /**
     * Notes   : 当前订单能不能查看物流
     *
     * @Date   : 2021/5/19 11:55
     * @Author : Mr.wang
     * @return bool
     */
    public function getIsLogisticShowAttribute(): bool
    {
        return in_array($this->state, [
            self::STATUS_DELIVERED,
            self::STATUS_SIGNED,
            self::REFUND_COMPLETED,
        ]);
    }

    public function getCanAction(): array
    {
        return [
            'pay'    => $this->canPay(),
            'cancel' => $this->canCancel(),
            'sign'   => $this->canSign(),
            'refund' => $this->canRefund(),
        ];
    }

}
