<?php
namespace Modules\Project\Services;

use Modules\Project\Entities\Order;
use Modules\Project\Entities\OrderGoods;
use Modules\Project\Entities\UserCoupon;
use Modules\Project\Services\Order\ChangeStatus;
use Modules\Project\Services\Order\Goods\GoodsCollection;
use Modules\Project\Services\Order\Goods\GoodsRow;
use SMG\Address\AddressModel;

class OrderService extends BaseService
{
    public function __construct(Order $order)
    {
        $this->model = $order;
    }

    /**
     * 新增订单
     *
     * @param $user_id
     * @param $data
     *
     * @throws \Exception
     *
     * @return $this
     */
    public function addOrder($user_id, $data)
    {
        $goods = $data['goods'];

        $s_goods_collect = new GoodsCollection();

        if (isset($data['coupon_id'])) {
            $s_goods_collect->setCoupon($data['coupon_id']);
            $s_goods_collect->use_coupon = true;
        }

        $s_goods_collect->setAddress($data['address_id']);

        $s_goods_collect->pushGoodsList($goods);

        $order_Goods = $s_goods_collect->goods(function (GoodsRow $row) {

            //删除购物车的商品
            $cart_service = new GoodsCartService();

            $item = $cart_service->_add([
                'id' => $row->model()->id,
                'spec' => $row->spec(),
                'qty' => $row->qty(),
            ]);

            $cart_service->_remove($item->rowId);

            $info = GoodsService::sellOut($row->model()->id, $row->spec(), $row->qty());

            $data = [
                'goods_id' => $row->model()->id,
                'goods_title' => $row->model()->title,
                //'spec' => json_encode($row->spec()),
                'qty' => $row->qty(),
                'selling_price' => $row->selling_price(),
                'total_price' => $row->total(),
                'remarks' => '',
            ];

            $data = new OrderGoods($data);

            return $data;
        });

        $insert_data['coupon_id'] = $s_goods_collect->coupon_id;

        $insert_data['address_id'] = $s_goods_collect->address_id;

        $order_no = $s_goods_collect->getUUID();

        $expires_time = intval(db_config('order_auto_expires_time', 45 * 60));
        if ($expires_time < 0) {
            $expires_time = 0;
        }

        $this->model = $this->model->create([
            'order_no' => $order_no,
            'user_id' => $user_id,
            'freight' => $s_goods_collect->freight(),
            'goods_price' => $s_goods_collect->goods_price(),
            'discount_amount' => $s_goods_collect->discount_amount(),
            'payable_amount' => $s_goods_collect->payable_amount(),
            'paid_amount' => 0,
            'status' => Order::STATUS_DEFAULT,
            'remarks' => isset($data['remarks']) ? $data['remarks'] : '',
            'expires_at' => date('Y-m-d H:i:s', time() + $expires_time),
        ]);

        $this->model->addLog(['before_status' => 0,'after_status' => Order::STATUS_DEFAULT , 'remarks' => '用户下单']);

        $this->copyAddressToOrder($data['address_id']);

        $this->model->orderGoods()->saveMany($order_Goods);

        return $this;
    }

    /**
     * 使用优惠券
     *
     * @param $coupon_id
     * @param $total_amount
     * @param $order_no
     *
     * @return float
     */
    protected function useCoupon($coupon_id, $total_amount, $order_no)
    {
        if (!$coupon_id) {
            return $total_amount;
        }

        $model = (new UserCoupon())->find($coupon_id);

        if (!$model) {
            throw \Illuminate\Validation\ValidationException::withMessages([
                'coupon_id' => ['优惠券不可用'],
            ]);
        }

        $order_coupon = new OrderCouponService($model);

        $order_coupon->setTotal($total_amount);

        $order_coupon->setUID($order_no);

        $amount = $order_coupon->userCoupon();

        return $amount;
    }

    /**
     * 拷贝地址
     *
     * @param $address_id
     *
     * @return $this
     */
    protected function copyAddressToOrder($address_id)
    {
        $info = AddressModel::find($address_id);

        if (!$info) {
            throw \Illuminate\Validation\ValidationException::withMessages([
                'address_id' => ['地址有误'],
            ]);
        }

        $create_data = $info->toArray();

        unset($create_data['id']);

        unset($create_data['created_at']);

        unset($create_data['updated_at']);

        $this->model->addresses()->save(new AddressModel($create_data));

        return $this;
    }

    /**
     * 关闭订单（用户）
     *
     * @param $user_id
     * @param $order_id
     * @param string $remarks
     *
     * @return bool
     */
    public static function userCancel($user_id, $order_id, $remarks = '')
    {
        $model = Order::where('user_id', $user_id)->where('id', $order_id)->where('status', Order::STATUS_DEFAULT)->get()->first();

        if ($model) {
            $order_servvice = new static($model);

            $order_servvice->cancel(
                [],
                [
                    'remarks' => $remarks ? $remarks : '用户取消订单',
                ]
            );

            return true;
        } else {
            return false;
        }
    }

    /**
     * 订单过期
     */
    public static function unpaidExpire()
    {
        Order::where('expires_at', '<', date('Y-m-d H:i:s'))->where('status', Order::STATUS_DEFAULT)->get()->each(function ($order) {
            $order_service = new OrderService($order);
            $order_service->cancel([], ['remarks' => '因长时间未支付，系统自动取消订单。']);
        });
    }

    /**
     * 系统确认
     */
    public static function sysConfirm()
    {
        $confirm_day = intval(db_config('order_auto_confirm_day', 15));
        if ($confirm_day < 0) {
            $confirm_day = 0;
        }
        Order::where('shipped_at', '<', date('Y-m-d H:i:s', time() - (24 * 3600 * $confirm_day)))->where('status', Order::STATUS_SHIPPED)->get()->each(function ($order) use ($confirm_day) {
            $order_service = new OrderService($order);
            $order_service->complete([], ['remarks' => "订单发货超过{$confirm_day}天，系统自动确认订单。"]);
        });
    }

    /**
     * 取消订单
     *
     * @param array $data
     * @param array $log_data
     *
     * @throws \Exception
     */
    public function cancel($data = [], $log_data = [])
    {
        $change_status = new ChangeStatus($this->model);

        $change_status->after_status = Order::STATUS_CANCEL;

        $change_status->before_status = $this->model->status;

        $change_status->save_data = $data;

        $change_status->save_log_data = [
            'remarks' => isset($log_data['remarks']) ? $log_data['remarks'] : '取消订单',
            'extend' => json_encode($data, true),
        ];

        $change_status->changeStatus();
    }

    /**
     * 支付成功
     *
     * @param $data
     */
    public function paymentSuccess($data = [], $log_data = [])
    {
        $change_status = new ChangeStatus($this->model);

        $change_status->after_status = Order::STATUS_PAID;

        $change_status->before_status = $this->model->status;

        if (!isset($data['paid_amount'])) {
            throw new \Exception('必须有支付金额');
        }

        $change_status->save_data = $data;

        $change_status->save_log_data = [
            'remarks' => isset($log_data['remarks']) ? $log_data['remarks'] : '支付成功',
            'extend' => json_encode($data, true),
        ];

        $change_status->changeStatus();
    }

    /**
     * 完成订单
     *
     * @param array $data
     * @param array $logData
     */
    public function complete($data = [], $log_data = [])
    {
        $change_status = new ChangeStatus($this->model);

        $change_status->after_status = Order::STATUS_COMPLETE;

        $change_status->before_status = $this->model->status;

        $change_status->save_data = $data;

        $change_status->save_log_data = [
            'remarks' => isset($log_data['remarks']) ? $log_data['remarks'] : '订单完成',
            'extend' => json_encode($data, true),
        ];

        $change_status->changeStatus();
    }

    /**
     * 发货（管理员）
     *
     * @param array $data
     * @param array $log_data
     *
     * @throws \Exception
     */
    public function delivery($data = [], $log_data = [])
    {
        $change_status = new ChangeStatus($this->model);

        $change_status->after_status = Order::STATUS_SHIPPED;

        $change_status->before_status = $this->model->status;

        $change_status->save_data = $data;

        $change_status->save_log_data = [
            'remarks' => isset($log_data['remarks']) ? $log_data['remarks'] : '订单发货',
            'extend' => isset($log_data['extend']) ? $log_data['extend'] : [],
        ];

        $change_status->changeStatus();
    }
}
