<?php

namespace App\Repositories\Customers;

use App\Common\Enums\HtTab;
use App\Exceptions\Api\ApiException;
use App\Modules\Enums\ErrorCode;
use App\Modules\Models\CouponOrder\CouponOrder;
use App\Modules\Models\Customer\Customer;
use App\Modules\Models\Machine\Machine;
use App\Modules\Models\Order\CouponShip;
use App\Modules\Models\Power\Power;
use App\Modules\Models\Production\Production;
use App\Modules\Models\Rent\Rent;
use App\Modules\Onenet\Facades\Onenet;
use App\Modules\Repositories\Rent\BaseRentRepository;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Log;

/**
 * Class EloquentHistoryRepository.
 */
class RentRepository extends BaseRentRepository
{

    public function makeOrder($params, $customer_id, $type = 1)
    {

        $machine = Machine::where(['mac_no' => $params['mac_no']])->first();
        if ($machine == null) {
            throw new ApiException(ErrorCode::MACHINE_NOT_EXIST, trans('api.error.machine_not_exist'));
        }
        $input = [
            'rent_no' => $this->createOrderNo(),
            'number' => $params['number'],
            'deposit' => $machine->deposit,
            'one_day_price' => $machine->one_day_price,
            'free_time' => $machine->free_time,
            'machine_id' => $machine->id,
            'customer_id' => $customer_id,
            'add_time' => date('Y-m-d H:i:s'),
            'spot_id' => $machine->spot_id,
            'business_id' => $machine->business_id,
            'rent_type' => $type,
        ];
        if(isset($params['powerType'])){
            $input['power_type'] = $params['powerType'];
        }
        return $this->create($input);
    }

    public function getNotOverRent($customer_id)
    {
        $where = [
            ['customer_id', '=', $customer_id],
            ['is_pay', '=', 1],
            ['is_over', '=', 0],
        ];
        $rent = Rent::where($where)->first();
        return $rent;
    }

    public function getNotOverRentByNo($rent_no)
    {
        $where = [
            ['rent_no', '=', $rent_no],
            ['is_pay', '=', 1],
            ['is_take', '=', 0],
            ['is_over', '=', 0],
        ];
        $rent = Rent::where($where)->first();
        return $rent;
    }

    public function checkOrder($customer_id)
    {
        $rent = $this->getNotOverRent($customer_id);
        if ($rent == null) {
            return ['status' => 1];
        }
        if ($rent->is_take) {
            return ['status' => 2, 'rent_no' => $rent->rent_no];
        }
        return ['status' => 3, 'rent_no' => $rent->rent_no];
    }


    function getRent($rent_no)
    {
        $where = [
            ['rent_no', '=', $rent_no],
        ];
        $rent = Rent::where($where)->first();
        if ($rent == null) {
            throw new ApiException(ErrorCode::RENT_NOT_EXIST, trans('api.error.rent_not_exist'));
        }
        return $rent;
    }

    function getNoPayRent($rent_no)
    {
        $where = [
            ['rent_no', '=', $rent_no],
            ['is_pay', '=', 0],
        ];
        $rent = Rent::where($where)->first();
        if ($rent == null) {
            throw new ApiException(ErrorCode::RENT_NOT_EXIST, trans('api.error.rent_not_exist'));
        }
        return $rent;
    }

    function makeRentPayed($rent_obj)
    {

        $rent_obj->is_pay = 1;
        $rent_obj->pay_time = date('Y-m-d H:i:s');
        try {
            $rent_obj->save();
        } catch (\Exception $e) {
            throw new ApiException(ErrorCode::DATABASE_ERROR, trans('api.error.database_error'));
        }
        return $rent_obj;
    }

    function makeRentTaked($rent_obj)
    {
        $rent_obj->is_take = 1;
        try {
            $rent_obj->save();
        } catch (\Exception $e) {
            throw new ApiException(ErrorCode::DATABASE_ERROR, trans('api.error.database_error'));
        }
        return $rent_obj;
    }

    function getRentInfo($rent_no)
    {
        return Rent::where('rent_no', $rent_no)->with(['spot', 'production'])->first();
    }

    function formatRentInfo($rent_obj)
    {
        $hatch_nos = [];
        if ($rent_obj->production) {
            foreach ($rent_obj->production as $production_obj) {
                $hatch_nos [] = $production_obj->rent_hatch_no;

            }
        }
        $data = [
            'spot_name' => $rent_obj->spot->spotname,
            'spot_code' => $rent_obj->spot->code,
            'pay_time' => $rent_obj->pay_time,
            'total' => $rent_obj->deposit * $rent_obj->number,
            'number' => $rent_obj->number,
            'hatch_nos' => $hatch_nos,
            'rent_no' => $rent_obj->rent_no,

        ];
        return $data;
    }


    function getProductionStatus($production_obj)
    {
        if ($production_obj->is_return) {
            //归还
            return 1;
        }
        if ($production_obj->is_out) {
            //使用中
            return 2;
        }
        //预约中
        return 3;
    }


    function takeOutSuccess($power_obj)
    {
        $where = [
            ['power_id', '=', $power_obj->id],
            ['is_out', '=', 0]
        ];
        $production_obj = Production::where($where)->orderBy('id', 'desc')->first();
        $production_obj->is_out = 1;
        $production_obj->save();
        return $production_obj;

    }

    function getMyRecord($customer_id, $page, $limit)
    {
        $where = [
            ['customer_id', '=', $customer_id],
            ['is_pay', '=', 1],
        ];
        return Rent::where($where)->orderBy('pay_time', 'desc')->skip($page * $limit)->take($limit)->with(['spot'])->get();
    }


    public function getRentStatus($rent_obj)
    {
        if ($rent_obj->is_cancel) {
            //交易取消
            return 4;
        }
        if ($rent_obj->is_over) {
            return 1;//交易结束
        }
        if ($rent_obj->is_take) {
            return 2;//使用中
        }
        if ($rent_obj->rent_type == 2) {
            return 3;//预约中
        }
        return 0;
    }


//    function shipment($ren_obj){
//        $powers = $this->getSomePowers($ren_obj->machine_id, $ren_obj->number);
//        if($powers == null){
//            return false;
//        }
//        return
//    }


    function changeCustomerDeposit($type, $customer_id, $money)
    {
        switch ($type) {
            case 1:
                Customer::where('id', $customer_id)->increment('deposit', $money);
                break;
            case 2:
                Customer::where('id', $customer_id)->decrement('deposit', $money);
                break;
            default:
                break;
        }

    }

    public function create($input)
    {
        DB::beginTransaction();
        try {
            $rent_obj = Rent::create($input);
            DB::commit();
        } catch (\Exception $e) {
            DB::rollBack();
            throw new ApiException(ErrorCode::DATABASE_ERROR, trans('api.error.database_error'));
        }
        return $rent_obj;
    }

//    public function set_rent_no($rent_obj)
//    {
//        $num = 2757031946 + $rent_obj->id;
//        $rent_no = 'R' . date('Ymd') . $num;
//        $rent_obj->rent_no = $rent_no;
//        return $rent_obj->save();
//    }


    function doTake($need_take)
    {

        $machine_obj = Machine::where('id', $need_take->machine_id)->first();
        if (!$machine_obj->life) {
            throw new ApiException(ErrorCode::MACHINE_NOT_life, trans('api.error.machine_ont_life'));
        }
        $lock = Redis::setnx('R_' . $need_take->machine_id, date("Y-m-d H:i:s"));

        if ($lock == 1) {
            //如果无人在取货，（获得锁成功）设置锁10秒自动删除
            Redis::expire('R_' . $need_take->machine_id, 10);
        } else {
            //别人正在使用
            return ['status' => 2];
        }
        $productions = $need_take->production()->get()->toArray();

        //onent发货

        Log::info("[onenet_open]:" . json_encode(array_column($productions, 'rent_hatch_no')));
        Onenet::openMultiple($machine_obj, $need_take->id, array_column($productions, 'rent_hatch_no'));

        $need_take->is_take = 1;
        $need_take->take_time = date('Y-m-d H:i:s');
        $need_take->save();
        return ['status' => 1];
    }

    function doReturn($power_obj, $machine_obj, $hatch_no, $backTime = '')
    {

        $where = [
            ['power_id', '=', $power_obj->id],
            ['is_out', '=', 1],
            ['is_return', '=', 0],

        ];
        $product = Production::where($where)->with('rent')->first();

        //计算租借费用
        $back_time = $backTime ? $backTime : date('Y-m-d H:i:s');
        $deposit = $product->rent->deposit;
        $number = $product->rent->number;

        $fee = $this->checkFee($product->rent->pay_time, $back_time, $product->rent->one_day_price, $product->rent->free_time);

        $total = $fee['total'] > $deposit ? $deposit : $fee['total'];
        $real_total = $total;


        if ($this->countBackTime($product)) {
            //最后归还的一个讲解器，关闭订单，使用优惠
            $product->rent->is_over = 1;
            $product->rent->over_time = Carbon::now();

            if ($total > 0) {
                $coupon = $this->getAvailableFullDiscountCoupon($product->rent->customer_id, $total, $product->rent->spot_id);
                if ($coupon !== null) {
                    //计算优惠
                    if ($coupon->discount_money > $total) {
                        $real_total = 0;
                    } else {
                        $real_total = $total - $coupon->discount_money;
                    }

                    //标记卡券已经核销记录订单使用卡券关系
                    $this->rentConsumeCoupon($product->rent->id, $coupon);

                }

            }


        }


        $refund_money = $deposit - $real_total;

        $product->rent->total = $product->rent->total + $total;
        $product->rent->real_total = $product->rent->real_total + $real_total;


        $product->is_return = 1;
        $product->return_machine_id = $machine_obj->id;
        $product->return_hatch_no = $hatch_no;
        $product->return_time = $back_time;
        $product->total = $total;

        $this->changeCustomerDeposit(2, $product->rent->customer_id, $product->rent->deposit);

        if ($refund_money > 0) {
            $product->rent->back_money = $product->rent->back_money + $refund_money;
            $refund_no = $this->createRefoundNo();
            $product->is_refund = 1;
            $product->refund_no = $refund_no;
            $product->refund_time = $back_time;
            $product->save();
            $product->rent->save();

            $res = [
                'status' => 1,
                'out_refund_no' => $refund_no,
                'out_trade_no' => $product->rent->rent_no,
                'total_fee' => $deposit * $number,
                'refund_fee' => $refund_money,
            ];
            return $res;
        }

        $product->save();
        $product->rent->save();

        return ['status' => 2];

    }

    function checkFee($rent_time, $back_time, $one_day_price, $free_time)
    {
        $use_time = strtotime($back_time) - strtotime($rent_time);
        $total = 0;
        $use_m = round($use_time / 60, 2);
        if ($use_time > $free_time * 60) {
            $datetime1 = date_create(date('Y-m-d', strtotime($rent_time)));
            $datetime2 = date_create(date('Y-m-d', strtotime($back_time)));
            $interval = date_diff($datetime1, $datetime2);
            $days = $interval->format('%R%a');
            if ($days == 0) {
                $total = $one_day_price;
            } elseif ($days > 0) {
                $total = $one_day_price * $days;
            }
        }
        return ['total' => $total, 'use_m' => $use_m];
    }


    function rentConsumeCoupon($order_id, $couponOrderObj)
    {

        $couponOrderObj->status = 2;
        $couponOrderObj->save();

        $insert = [
            'order_id' => $order_id,
            'coupon_order_id' => $couponOrderObj->id,
        ];
        CouponShip::insert($insert);

    }

    function getAvailableFullDiscountCoupon($customer_id, $total, $spot_id)
    {

        $where = [
            ['coupon_order.customer_id', '=', $customer_id],
            ['coupon_order.status', '=', 1],
            ['coupon_order.expire_time', '>=', date('Y-m-d')],
            ['coupon_type.discount', '<=', $total],
            ['coupon_type.type', '=', 2],
            //['coupon_order.spot_id', '=', $spot_id]
        ];

        $coupon = CouponOrder::where($where)
            ->where(function ($query) use($spot_id) {
                $query->where('coupon_order.spot_id', '=', $spot_id)
                    ->orWhere('coupon_type.auto_send', '=', 1);
            })
            ->rightjoin('coupon_type', 'coupon_order.coupon_type_id', '=', 'coupon_type.id')
            ->orderBy('discount_money', 'desc')
            ->select('coupon_order.*', 'coupon_type.type', 'coupon_type.discount', 'coupon_type.auto_send', 'coupon_type.schedule_time', 'coupon_type.discount_money')
            ->first();
        Log::info('coupon: '.$coupon.'; spot_id: '.$spot_id);
        return $coupon;
    }

    function getRentOutDetail($rent_no)
    {
        $rent_detail = Rent::where('rent_no', $rent_no)->with(['production'])->first();
        if ($rent_detail == null) {
            throw new ApiException(ErrorCode::RENT_NOT_EXIST, trans('api.error.rent_not_exist'));
        }
        return $rent_detail;
    }

    function getOutHatchs($rent_obj)
    {
        $success_hatch_nos = [];
        $fail_hatch_nos = [];
        foreach ($rent_obj->production as $production) {
            if ($production->is_out) {
                $success_hatch_nos[] = $production->rent_hatch_no;
            } else {
                $fail_hatch_nos[] = $production->rent_hatch_no;
            }
        }

        return ['success_hatch_nos' => $success_hatch_nos, 'fail_hatch_nos' => $fail_hatch_nos];
    }

    function getRentDetail($rent_id)
    {
        $where = [
            ['id', '=', $rent_id],
            ['expire_handle', '=', 0]
        ];
        $rent_detail = Rent::where($where)->with(['production'])->first();
        if ($rent_detail == null) {
            throw new ApiException(ErrorCode::RENT_NOT_EXIST, trans('api.error.rent_not_exist'));
        }
        return $rent_detail;
    }

    function expireHandleStatusChange($rent_obj, $fail_hatchs)
    {
        if (count($fail_hatchs) == $rent_obj->number) {
            $rent_obj->is_cancel = 1;
            $rent_obj->is_over = 1;
        }
        $rent_obj->expire_handle = 1;
        $rent_obj->save();
    }


    function getOverHatch($productions_obj)
    {
        $hatch_nos = [];
        foreach ($productions_obj as $production) {
            $hatch_nos[] = $production->rent_hatch_no;
        }
        return $hatch_nos;
    }

    function isLastOut($rent_obj, $product_obj)
    {
        if ($rent_obj->number == 1) {
            return ['status' => true, 'hatch_nos' => [$product_obj->rent_hatch_no]];
        }
        $where2 = [
            ['rent_id', '=', $rent_obj->id],
            ['is_out', '=', 1],
        ];
        $products = Production::where($where2)->get()->toArray();
        if ($rent_obj->number == count($products)) {
            return ['status' => true, 'hatch_nos' => array_column($products, 'rent_hatch_no')];
        }
        return ['status' => false];
    }

    function countBackTime($product)
    {
        if ($product->rent->number == 1) {
            return true;
        }
        $where2 = [
            ['rent_id', '=', $product->rent_id],
            ['is_return', '=', 1],
        ];
        $time = Production::where($where2)->count();
        if ($product->rent->number == $time + 1) {
            return true;
        }
        return false;
    }


    function getSomePowers($machine_id, $number, $power_type = 'E2')
    {
        $where = [
            ['has_power', '>', '75'],
            ['machine_id', '=', $machine_id],
            ['status', '=', 2],
            ['is_miss', '=', 0],
            ['power_type', '=', $power_type]
        ];
        /**按id 排---start
        $powers = Power::where($where)->limit($number)->get()->toArray();
        if (count($powers) != $number) {
            return [];
        }
        ---end----*/
        /**随机排序---start*/
        $powers = Power::where($where)->get()->toArray();
        if (count($powers) < $number) {
            return [];
        }
        shuffle($powers);
        $powers = array_slice($powers, 0, $number);
        /**---end----*/
        return $powers;
    }

    function makeOrderDetail($rent_obj, $powers)
    {
        $insert_data = [];
        foreach ($powers as $key => $v) {
            $insert_data[$key]['rent_id'] = $rent_obj->id;
            $insert_data[$key]['rent_machine_id'] = $rent_obj->machine_id;
            $insert_data[$key]['rent_hatch_no'] = $v['hatch_no'];
            $insert_data[$key]['power_id'] = $v['id'];
            $insert_data[$key]['power_no'] = $v['power_no'];
            $insert_data[$key]['spot_id'] = $rent_obj->spot_id;
            $insert_data[$key]['business_id'] = $rent_obj->business_id;
            $insert_data[$key]['created_at'] = date('Y-m-d H:i:s');
        }
        return $this->insertProduct($insert_data);
    }

    function makeOrderRefunded($rent_obj, $refund_no)
    {
        $rent_obj->is_cancel = 1;
        $rent_obj->is_over = 1;
        $rent_obj->back_money = $rent_obj->deposit * $rent_obj->number;
        $rent_obj->refund_no = $refund_no;
        $rent_obj->save();
    }

    function insertProduct($insert_data)
    {
        $production = new Production();
        DB::beginTransaction();
        try {
            $insert = $production::insert($insert_data);
            DB::commit();
        } catch (\Exception $e) {
            DB::rollBack();
            throw new ApiException(ErrorCode::DATABASE_ERROR, trans('api.error.database_error'));
        }
        return $insert;
    }

    /**
     * 获取最后一次扫码记录
     * @param $customer_id
     * @return mixed
     */
    public function getLastOrder($customer_id)
    {
        $where = [
            ['customer_id', '=', $customer_id]
        ];
        $res = Rent::where($where)->orderBy('id', 'desc')->with(['spot'])->first();
        return $res;
    }

    /**
     * 处理oneNet出货业务逻辑
     * @param $data
     * @return bool
     * @throws ApiException
     */

    function takeResult($data)
    {
        $where = [
            ['power_id', '=', $data['power_id']],
            ['is_take', '=', 0],

        ];
        $production = Productio::where($where)->first();
        if ($production == null) {
            throw new ApiException(ErrorCode::PRODUCTION_NOT_EXIST, trans('api.error.production_not_exist'));
        }
        $production->is_take = 1;
        $production->take_time = date('Y-m-d H:is');
        $production->save();
        //todo 通知长链接 消息通知
        return true;
    }

    /**
     * 处理oneNet归还充电宝业务逻辑
     * @param $data
     * @return bool
     * @throws ApiException
     */

    function returnResult($data)
    {
        $where = [
            ['power_id', '=', $data['power_id']],
            ['is_take', '=', 1],
            ['is_return', '=', 0],

        ];
        $production = Productio::where($where)->first();
        if ($production == null) {
            throw new ApiException(ErrorCode::PRODUCTION_NOT_EXIST, trans('api.error.production_not_exist'));
        }

        $production->is_return = 1;
        $production->take_time = date('Y-m-d H:is');
        $production->save();
        //todo 处理退款 消息通知

        return true;
    }

    /**
     * 生成订单单号
     */
    function createOrderNo()
    {
        return HtTab::RENT_ORDER . date('Ymd') . str_pad(mt_rand(1, 9999999999), 10, '0', STR_PAD_LEFT);
    }

    /**
     * 生成退款单号
     */
    function createRefoundNo()
    {
        return HtTab::RENT_REFUND . date('Ymd') . str_pad(mt_rand(1, 9999999999), 10, '0', STR_PAD_LEFT);
    }

}
