<?php

namespace App\Services\Pay;

use App\Exceptions\AlertException;
use App\Exceptions\ApiException;
use App\Http\Controllers\Order;
use App\Models\CouponModel;

class CouponService
{


    /**
     * @var int uid
     */
    public $uid;


    /**
     * 商品种类
     * @var
     */
    private $goods_scope;


    /**
     * 优惠券ID
     * @var int
     */
    public $coupon_id;


    private $attributes = [];


    /**
     * 生成数量
     * @var int
     */
    public $number = 1;


    /**
     * 批号ID
     * @var int
     */
    public $batch_id;


    /**
     * 商品ID
     * @var int
     */
    public $goods_id;


    /**
     * 折扣
     * @var int
     */
    public $discount = 0;


    /**
     * 商品总价格
     * @var int
     */
    public $total_amount;


    /**
     * 优惠后价格
     * @var int
     */
    public $settlement_total_amount;


    /**
     * 优惠券金额
     * @var int
     */
    public $coupon_amount;


    /**
     * 优惠券
     * @var CouponModel
     */
    private $coupon;


    /**
     * 设置uid
     * @param  int  $uid
     * @return $this
     */
    public function setUid(int $uid)
    {
        $this->uid = $uid;

        return $this;
    }


    public function getUid(): int
    {
        return $this->uid;
    }


    /**
     * 设置优惠券ID
     * @param  int  $id
     * @return $this
     */
    public function setCouponId(int $id)
    {
        $this->coupon_id = $id;

        return $this;
    }


    public function getCouponId(): int
    {
        return $this->coupon_id;
    }


    /**
     * 设置商品ID
     * @param  int  $id
     * @return $this
     */
    public function setGoodsId(int $id)
    {
        $this->goods_id = $id;

        return $this;
    }


    /**
     * 获取商品ID
     * @return int
     */
    public function getGoodsId(): int
    {
        return $this->goods_id;
    }


    /**
     * 设置批量ID
     * @param $batch_id
     * @return $this
     */
    public function setBatchId($batch_id)
    {
        $this->batch_id = $batch_id;

        return $this;
    }


    /**
     * 获取批号ID
     * @return string
     */
    public function getBatchId(): string
    {
        return $this->batch_id;
    }


    /**
     * 设置券的数量
     * @param  int  $number
     * @return $this
     */
    public function setNumber(int $number)
    {
        $this->number = $number;

        return $this;
    }


    /**
     * 优惠券信息
     * @return mixed
     * @throws AlertException
     */
    public function getCoupon()
    {
        if (!isset($this->coupon_id)) {
            throw new AlertException("coupon_id 未设置", 500);
        }

        if (!isset($this->coupon)) {
            $this->coupon = CouponModel::find($this->coupon_id);
        }
        return $this->coupon;
    }


    /**
     * 使用优惠券
     * @param  int  $order_id
     * @return mixed
     * @throws AlertException
     * @throws ApiException
     */
    public function use($order_id = 0)
    {
        $this->getCoupon();

        $settlement_total_amount = $this->getSettlementAmount();

        if ($order_id) {
            $this->coupon->order_id = $order_id;
            $this->coupon->used_at = time();
        } else {
            $this->coupon->used_at = time();
        }
        $this->coupon->save();

        return $settlement_total_amount;
    }


    /**
     * 优惠券返还
     * @return bool
     * @throws AlertException
     */
    public function unUse()
    {
        $this->getCoupon();

        try {
            $this->coupon->order_id = 0;
            $this->coupon->used_at = 0;
            if ($this->coupon->save()) {
                return true;
            }
        } catch (\Exception $e) {
            app('sentry')->captureException($e);
        }
        return false;
    }


    /**
     * 计算优惠券
     * @return float|int
     * @throws AlertException
     * @throws ApiException
     */
    public function getSettlementAmount()
    {
        $this->getCoupon();

        if (!$this->isExist()) {
            throw new ApiException("兑换码不正确哦");
        }

        if (!$this->coupon->isOwner($this->uid)) {
            throw new ApiException("兑换码不正确哦");
        }

        if ($this->coupon->isUsed()) {
            throw new ApiException("卡券已使用");
        }

        if (!$this->coupon->isOpened()) {
            throw new ApiException("卡券未到使用时间");
        }

        if ($this->coupon->isOverdue()) {
            throw new ApiException("卡券过期啦");
        }

        if (!$this->coupon->isGoodsScope($this->goods_id)) {
            throw new ApiException("该商品/业务不可使用此优惠券");
        }

        if (!$this->coupon->isSatisfyPrice($this->goods_id)) {
            throw new AlertException("未满优惠券使用金额");
        }

        $goods = $this->getGoods();
        $this->total_amount = $goods['total_fee'];

        switch ($this->coupon->type) {
            case "无门槛券":
            case "72小时入场券":
            case "满减券":
                $coupon_amount = ($this->coupon->coupon_amount > $this->total_amount)
                    ? $this->total_amount
                    : $this->coupon->coupon_amount;
                break;
            case "折扣券":
                $coupon_amount = floor($goods['total_fee'] * (1 - $this->coupon->discount / 10) / 10) * 10;
                break;
            default:
                throw new AlertException("未定义的卡券");
        }

        $this->coupon_amount = $coupon_amount;
        $this->settlement_total_amount = (int)($this->total_amount - $this->coupon_amount);

        return $this->settlement_total_amount;
    }


    /**
     * 获取商品信息
     * @return mixed
     */
    public function getGoods()
    {
        return Order::GOODS[$this->goods_id];
    }


    /**
     * 是否存在
     * @return bool
     * @throws AlertException
     */
    public function isExist()
    {
        $this->getCoupon();

        return $this->getCoupon() ? true : false;
    }


    /**
     * 是否主人
     * @return bool
     * @throws AlertException
     * @throws ApiException
     */
    public function isOwner()
    {
        $this->getCoupon();

        if (!isset($this->uid)) {
            throw new ApiException("uid 未设置", 500);
        }

        return ($this->coupon->uid == $this->uid) ? true : false;
    }

    /**
     * 是否使用
     * @return bool
     * @throws AlertException
     */
    public function isUse()
    {
        $this->getCoupon();

        return ($this->coupon->used_at != 0) ? true : false;
    }


    /**
     * 是否过期
     * @return bool
     * @throws AlertException
     */
    public function isOverdue()
    {
        $this->getCoupon();

        return ($this->coupon->overdue_at <= time()) ? true : false;
    }


    public function isOpen()
    {
        $this->getCoupon();

        return ($this->coupon->open_at <= time()) ? true : false;
    }

    /**
     * 是否符合商品
     * @return bool
     * @throws AlertException
     * @throws ApiException
     */
    public function isGoods()
    {
        $this->getCoupon();

        if (!isset($this->goods_id)) {
            throw new ApiException("goods_id 未设置", 500);
        }

        $goods_list = $this->getGoodsScope($this->coupon->goods_scope);

        return (in_array($this->goods_id, $goods_list)) ? true : false;
    }


    /**
     * 获取此种类的商品
     * @param $goods_scope
     * @return mixed
     */
    public function getGoodsScope($goods_scope)
    {
        return CouponModel::GOODS_TYPE[$goods_scope];
    }


    /**
     * 是否满足满减价格
     * @return bool
     */
    public function isSatisfy()
    {
        $goods = $this->getGoods();
        return ($goods['total_fee'] >= $this->coupon->min_amount) ? true : false;
    }


    /**
     * 生成券
     * @return bool
     */
    public function make()
    {
        $data = [];
        $number = $this->number;

        while ($number) {
            $attributes = $this->attributes;
            $attributes['code'] = $this->getCode();

            array_push($data, $attributes);
            $number--;
        }
        return CouponModel::insert($data);
    }


    /**
     * vip券
     * @return $this
     * @return bool
     */
    public function makeVip()
    {
        $this->batch_id = "vip" . date("Ym");

        $this->attributes = [
            'uid' => $this->uid,
            'goods_scope' => 'pair',
            'type' => '72小时入场券',
            'name' => '72小时CP直升入场券',
            'describe' => 'SVIP专属，直升全场最高匹配成功率',
            'coupon_amount' => 990,
            'min_amount' => 990,
            'created_at' => time(),
            'updated_at' => time(),
            'get_at' => time(),
            'open_at' => time(),
            'overdue_at' => now()->addWeek(1)->addHour(12)->getTimestamp(),
            'batch_id' => $this->getBatchId(),
        ];

        return $this->make();
    }


    /**
     * 签到超级会员满减折扣
     * @return $this
     * @return bool
     */
    public function makeSignSvip()
    {
        $this->batch_id = "sign" . date("Ym");

        $this->attributes = [
            'uid' => $this->uid,
            'goods_scope' => 'super_vip',
            'type' => '满减券',
            'name' => '分配对象超级会员满减券',
            'describe' => '开通SVIP时使用，可享受相应优惠',
            'coupon_amount' => 900,
            'min_amount' => 1000,
            'created_at' => time(),
            'updated_at' => time(),
            'get_at' => time(),
            'open_at' => time(),
            'overdue_at' => now()->addMonth(1)->getTimestamp(),
            'batch_id' => $this->getBatchId(),
        ];
        return $this->make();
    }

    /**
     * 签到72小时折扣
     * @return $this
     * @return bool
     */
    public function makeSign72Dis()
    {
        $this->batch_id = "sign" . date("Ym");

        $this->attributes = [
            'uid' => $this->uid,
            'goods_scope' => 'pair',
            'type' => '折扣券',
            'name' => '72小时CP报名折扣券',
            'describe' => '非免费入场时，可享受相应折扣',
            'discount' => 6.8,
            'min_amount' => 990,
            'created_at' => time(),
            'updated_at' => time(),
            'get_at' => time(),
            'open_at' => time(),
            'overdue_at' => now()->addMonth(1)->getTimestamp(),
            'batch_id' => $this->getBatchId(),
        ];
        return $this->make();
    }


    /**
     * 生成兑换码
     * @return string
     */
    private function getCode()
    {
        return \getChars(8);
    }
}
