<?php
// +----------------------------------------------------------------------
// | A3Mall
// +----------------------------------------------------------------------
// | Copyright (c) 2020 http://www.a3-mall.com All rights reserved.
// +----------------------------------------------------------------------
// | Author: xzncit <158373108@qq.com>
// +----------------------------------------------------------------------

namespace app\api\service;

use think\facade\Db;
use think\facade\Request;
use app\common\library\utils\BC;
use app\common\exception\BaseException;
use app\common\model\Region as RegionModel;
use app\common\model\Users as UsersModel;
use app\common\model\users\UsersAddress as UsersAddressModel;
use app\common\model\users\UsersCart as UsersCartModel;
use app\common\model\users\UsersInvoice as UsersInvoiceModel;
use app\api\model\users\UsersCoupon as UsersCouponModel;
use app\common\model\order\Order as OrderModel;
use app\common\model\order\OrderGoods as OrderGoodsModel;
use app\common\model\order\OrderAddress as OrderAddressModel;
use app\common\model\order\OrderInvoice as OrderInvoiceModel;
use app\common\service\Users as UsersService;
use app\common\enum\Terminal;
use app\common\model\goods\Goods as GoodsModel;
use app\common\model\goods\GoodsItem as GoodsItemModel;
use app\common\service\promotion\Consume as ConsumeService;
use app\common\service\promotion\Shipping as ShippingService;
use app\common\service\promotion\Rebate as RebateService;
use app\common\service\promotion\Gift as GiftService;
use app\common\enum\Order as OrderEnum;
use app\common\model\promotion\BargainUsers as BargainUsersModel;

/**
 * @package app\api\service
 * @class Checkout
 * @author xzncit 2024-03-14
 */
class Checkout {

    /**
     * 下单详细信息
     * @param array $params
     * @return array
     * @throws BaseException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function detail($params=[]){
        if(empty($params["type"])){
            throw new BaseException("页面参数错误",0);
        }

        $class = "app\\api\\service\\checkout\\" . ucfirst($params["type"]);
        if(!class_exists($class)){
            throw new BaseException("您参与的活动不存在",0);
        }

        $condition = [];
        $condition[] = ["user_id","=",UsersService::get("id",0)];
        if(!empty($params["address_id"])){
            $condition[] = ["id","=",$params["address_id"]];
        }else{
            $condition[] = ["is_default","=",1];
        }

        $address = UsersAddressModel::where($condition)->find();

        $order = [];
        $goods = invoke($class);
        $order["goods"] = $goods->getData($params,$address)[0];
        list($goodsAmount,$goodsId) = self::orderAmount($order,$params,$address);
        $order["type"]  = OrderEnum::getType($params["type"]);
        $order["goods"] = array_merge($order["goods"],GiftService::goods($order));
        $order = array_merge($order,$goodsAmount);
        $order["coupon"] = self::coupon($order,$goodsId);
        return $order;
    }

    /**
     * @param array $params
     * @return array
     * @throws BaseException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function create($params=[]){
        if(empty($params["type"])){
            throw new BaseException("页面参数错误",0);
        }

        $address = UsersAddressModel::withoutField("id")->where(["id"=>$params["address_id"]??0,"user_id"=>UsersService::get("id",0)])->findOrEmpty()->toArray();
        if(empty($address)){
            throw new BaseException("请选择收货地址",0);
        }

        $params["invoice_id"] = intval($params["invoice_id"]??0);
        if($params["invoice_id"] > 0){
            $invoice = UsersInvoiceModel::withoutField("id")->where(["id"=>$params["invoice_id"]??0,"user_id"=>UsersService::get("id",0)])->findOrEmpty()->toArray();
            if(empty($invoice)){
                throw new BaseException("您选择的发票信息不合法",0);
            }
        }

        $class = "app\\api\\service\\checkout\\" . ucfirst($params["type"]);
        if(!class_exists($class)){
            throw new BaseException("您参与的活动不存在",0);
        }

        $goods = invoke($class);
        $goodsData = $goods->getData($params,$address);
        $order = [];
        $order["user_id"]     = UsersService::get("id",0);
        $order["order_no"]    = orderNo();
        $order["message"]     = $params["message"]??"";
        $order["source"]      = Terminal::getTerminalNo(Request::header("Client-Type","h5"));
        $order["create_time"] = time();
        $order["address"]     = $address;
        $order["invoice"]     = $invoice??[];
        $order["goods"]       = $goodsData[0];

        // 检查商品库存
        foreach($order["goods"] as $v){
            if($v["goods_total_nums"] > $v["store_nums"]){
                throw new BaseException("{$v['goods_name']}商品库存不足",0);
            }
        }

        $orderData            = self::orderAmount($order,$params,$address);
        $order                = array_merge($order,$orderData[0]);
        $order["type"]        = OrderEnum::getType($goodsData[1]["type"]);
        $order["goods"]       = array_merge($order["goods"],GiftService::goods($order));
        $order["point"]       = ConsumeService::reward($order);
        $order["promoter_id"] = $goodsData[1]["promoter_id"];

        if($order["real_point"] > UsersService::auth("score",0)){
            throw new BaseException("您的积分不足，不允许兑换该商品",0);
        }

        $order_id = OrderModel::transaction(function () use($order){
            $order_id = OrderModel::create($order)->id;
            $order["address"]["order_id"] = $order_id;
            foreach($order["goods"] as $value){
                $value["order_id"]   = $order_id;
                $value["goods_array"] = !empty($value["goods_array"]) ? json_encode($value["goods_array"],JSON_UNESCAPED_UNICODE) : "";
                OrderGoodsModel::create($value);
            }

            $region = [
                "province"  => $order["address"]["province"],
                "city"      => $order["address"]["city"],
                "area"      => $order["address"]["area"]
            ];

            foreach($region as $key=>$val){
                $order["address"][$key] = RegionModel::where("id",$val)->value("name","");
            }

            OrderAddressModel::create($order["address"]);
            if(!empty($order["invoice"])){
                $order["invoice"]["order_id"] = $order_id;
                OrderInvoiceModel::create($order["invoice"]);
            }

            foreach($order["goods"] as $value){
                if($value["sku_id"] > 0){
                    GoodsItemModel::where(["goods_id"=>$value["goods_id"],"sku_id"=>$value["sku_id"]])->save([
                        "store_nums"=>Db::raw("store_nums-".$value["goods_total_nums"])
                    ]);
                }else{
                    GoodsModel::where("id",$value["goods_id"])->save([
                        "store_nums"=>Db::raw("store_nums-".$value["goods_total_nums"])
                    ]);
                }
            }

            if($order["order_amount"] <= 0){
                OrderModel::where("id",$order_id)->save([
                    "status"=>3,
                    "pay_status"=>2,
                    "pay_time"=>time()
                ]);

                if($order["type"] == 3){
                    BargainUsersModel::where(["user_id"=>UsersService::get("id"),"bargain_id"=>$order["promoter_id"]])->save(["status"=>2]);
                }
            }

            // 积分订单
            if($order["real_point"] > 0 && $order["type"] == 6){
                UsersModel::where("id",UsersService::get("id"))->save([
                    "score"=>Db::raw("score-" . $order["real_point"])
                ]);

            }

            return $order_id;
        });

        // 清理购物车商品
        if($order_id > 0 && $params["type"] == "cart"){
            UsersCartModel::where("user_id",UsersService::get("id",0))->where("id","in",$params["id"])->delete();
        }

        // 修改优惠券使用状态
        if($order_id > 0 && !empty($params["coupon_id"])){
            UsersCouponModel::withJoin("coupon")->where([
                "id"        => $params["coupon_id"],
                "user_id"   => UsersService::get("id",0)
            ])->save([
                "order_id"  => $order_id,
                "status"    => 1
            ]);
        }

        return $order_id;
    }

    protected static function orderAmount($data,$params,$address){
        $order = [
            "coupon_amount"   => 0,
            "real_point"      => 0,
            "real_amount"     => 0,
            "real_freight"    => 0,
            "order_amount"    => 0,
            "payable_freight" => 0,
            "payable_amount"  => 0
        ];

        $goodsId = [];
        foreach($data["goods"] as $value){
            $goodsId[] = $value["goods_id"];
            $order["real_point"]   = BC::add($value["real_point"]??0,$order["real_point"],0);
            $order["real_amount"]  = BC::add($value["total_price"],$order["real_amount"]);
            $order["real_freight"] = BC::add($value["real_freight"],$order["real_freight"]);
        }

        if(!empty($params["coupon_id"])){
            $condition   = [];
            $condition[] = ["users_coupon.id","=",$params["coupon_id"]];
            $condition[] = ["users_coupon.user_id","=",UsersService::get("id",0)];
            $condition[] = ["users_coupon.end_time",">",time()];
            $condition[] = ["coupon.order_amount","<=",$order["real_amount"]];
            $usersCoupon = UsersCouponModel::withJoin("coupon")->where($condition)->find();
            if(!empty($usersCoupon)){
                $coupon = $usersCoupon["coupon"];
                if($coupon["type"] == 1){
                    $order["coupon_amount"] = $coupon["reduce_price"];
                }else{
                    $order["coupon_amount"] = round(((100 - $coupon["discount"]) / 100) * $order["real_amount"],2);
                }

                if($order["coupon_amount"] <= 0) {
                    $order["coupon_amount"] = 0;
                }
            }
        }

        $order["payable_freight"] = $order["real_freight"];
        $order["real_freight"]    = ShippingService::freeFreight($order["real_amount"],$order["real_freight"],$address);
        $order["payable_amount"]  = BC::add($order["real_freight"],$order["real_point"] > 0 ? 0 : $order["real_amount"]);
        $order["order_amount"]    = $order["payable_amount"] > $order["coupon_amount"] ? BC::sub($order["payable_amount"],$order["coupon_amount"]) : 0.00;
        $order["discount"]        = RebateService::discount($order["order_amount"]);
        $orderAmount              = BC::sub($order["order_amount"],$order["discount"]);
        $order["order_amount"]    = $orderAmount <= 0 ? 0 : $orderAmount;
        return [$order,$goodsId];
    }

    protected static function coupon($order=[],$goodsId=[]){
        $condition = [];
        $condition[] = ["users_coupon.user_id","=",UsersService::get("id",0)];
        $condition[] = ["users_coupon.status","=",0];
        $condition[] = ["users_coupon.end_time",">",time()];
        $condition[] = ["coupon.order_amount","<=",$order["real_amount"]];
        $list = UsersCouponModel::withJoin("coupon")->where($condition)->order("users_coupon.id","DESC")->select()->map(function($value)use($goodsId){
            $coupon = $value["coupon"];

            $amount = $coupon["reduce_price"];
            if($coupon["type"] == 2){
                $amount = number_format(($coupon["discount"] / 100) * 10,1);
            }

            $result = [
                "id"            => $value["id"],
                "name"          => $coupon["name"],
                "type"          => $coupon["type"],
                "apply_range"   => $coupon["apply_range"],
                "amount"        => $amount,
                "order_amount"  => $coupon["order_amount"],
                "disable"       => false,
                "time"          => date("Y-m-d",$value["end_time"])
            ];

            if($value["apply_range"] == 1){
                if(empty($value["goods_list"])){
                    $result["disable"] = true;
                }else{
                    $array = explode(",",$value["goods_list"]);
                    foreach($array as $v){
                        $result["disable"] = in_array($v,$array) ? false : true;
                    }
                }
            }else if($value["apply_range"] == 2){
                if(!empty($value["goods_list"])){
                    $array = explode(",",$value["goods_list"]);
                    foreach($array as $v){
                        $result["disable"] = in_array($v,$array) ? true : false;
                    }
                }
            }

            return $result;
        });

        return $list;
    }

    /**
     * 地址信息
     * @return UsersAddressModel[]|array|\think\Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function address(){
        return UsersAddressModel::where("user_id",UsersService::get("id",0))->select()->map(function ($res){
            $res["address"] = RegionModel::getArea([$res["province"],$res["city"],$res["area"]]," ") . $res["address"];
            return [
                "id"         => $res["id"],
                "name"       => $res["accept_name"],
                "mobile"     => $res["mobile"],
                "address"    => $res["address"],
                "is_default" => $res["is_default"],
                "checked"    => false
            ];
        });
    }

    /**
     * 开票
     * @return UsersInvoiceModel[]|array|\think\Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function invoice(){
        return UsersInvoiceModel::where("user_id",UsersService::get("id",0))->select()->map(function ($res){
            return [
                "id"          => $res["id"],
                "type"        => $res["header_type"],
                "name"        => $res["name"],
                "mobile"      => $res["drawer_phone"],
                "email"       => $res["email"],
                "duty_number" => $res["duty_number"]
            ];
        });
    }

}