<?php

namespace App\Services;

use App\OwnerFeeDetail;
use App\Services\common\BatchUpdateService;
use App\Services\common\QueryService;
use App\Traits\ModelSearchWay;
use App\Waybill;
use App\WaybillAuditLog;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Ramsey\Uuid\Uuid;
use App\Traits\ServiceAppAop;


class WaybillService
{
    use ServiceAppAop;
    use ModelSearchWay;
    protected $modelClass=Waybill::class;
    /**
     * @param array $param
     * @return Builder
     */
    private function conditionQuery(array $param){
        $waybills = Waybill::filterAuthorities()->with(['owner','logistic','originationCity','destinationCity.parent',
            'uploadFile','amountUnit','warehouseWeightUnit','carrierWeightUnit','district','order',
            'warehouseWeightUnitOther','carrierWeightUnitOther','carType','uploadFile','waybillAuditLogs.user'])
            ->selectRaw('waybills.* ,waybill_on_tops.id top_id ,waybill_on_tops.remark,waybill_on_tops.updated_at top_update')
            ->leftJoin('waybill_on_tops','waybill_on_tops.waybill_id','=','waybills.id')
            ->whereNull('waybill_on_tops.deleted_at')
            ->orderBy('waybill_on_tops.updated_at','desc')
            ->orderBy('waybills.id','desc');
        if ($param["owner_id"] ?? false){
            $ownerIds = explode(",",$param["owner_id"]);
            $waybills->where(function ($query)use($ownerIds){
                /** @var Builder $query */
                $query->whereIn("waybills.owner_id",$ownerIds)->orWhereHas("order",function ($query)use($ownerIds){
                    /** @var Builder $query */
                    $query->whereIn("owner_id",$ownerIds);
                });
            });
            unset($param["owner_id"]);
        }
        if ($param["destination"] ?? false){
            $destination = $param["destination"];
            $waybills->where(function ($query)use($destination){
                /** @var Builder $query */
                $query->where("waybills.destination","like",$destination."%")->orWhereHas("order",function ($query)use($destination){
                    /** @var Builder $query */
                    $query->where("address",'like',$destination."%");
                });
            });
            unset($param["destination"]);
        }
        if ($param["recipient"] ?? false){
            $recipient = $param["recipient"];
            $waybills->where(function ($query)use($recipient){
                if (strpos($recipient, ',') || strpos($recipient, '，') || strpos($recipient, ' ')) {
                    $arr = array_filter(preg_split('/[,， ]+/is', $recipient));
                    /** @var Builder $query */
                    $query->whereIn("waybills.recipient",$arr)->orWhereHas("order",function ($query)use($arr){
                        /** @var Builder $query */
                        $query->whereIn("consignee_name",$arr);
                    });
                } else {
                    /** @var Builder $query */
                    $query->where("waybills.recipient","like",$recipient."%")->orWhereHas("order",function ($query)use($recipient){
                        /** @var Builder $query */
                        $query->where("consignee_name",'like',$recipient."%");
                    });
                }

            });
            unset($param["recipient"]);
        }
        if ($param["recipient_mobile"] ?? false){
            $recipientMobile = $param["recipient_mobile"];
            $waybills->where(function ($query)use($recipientMobile){
                if (strpos($recipientMobile, ',') || strpos($recipientMobile, '，') || strpos($recipientMobile, ' ')) {
                    $arr = array_filter(preg_split('/[,， ]+/is', $recipientMobile));
                    /** @var Builder $query */
                    $query->whereIn("waybills.recipient_mobile",$arr)->orWhereHas("order",function ($query)use($arr){
                        /** @var Builder $query */
                        $query->whereIn("consignee_phone",$arr);
                    });
                } else {
                    /** @var Builder $query */
                    $query->where("waybills.recipient_mobile","like",$recipientMobile."%")->orWhereHas("order",function ($query)use($recipientMobile){
                        /** @var Builder $query */
                        $query->where("consignee_phone",'like',$recipientMobile."%");
                    });
                }

            });
            unset($param["recipient_mobile"]);
        }

        if (($param["updated_at_start"] ?? false) || ($param["updated_at_end"] ?? false)){
            $waybills->whereIn("waybills.status",['已完结','无模型']);
        }

//        if($param['carrier_bill'] ?? false){    // 承运商单号
//            $this->searchWay($waybills,$param['carrier_bill'],'waybills.carrier_bill');
//            unset($param['carrier_bill']);
//        }
//        if($param['waybill_number'] ?? false) { // 运单号
//            $this->searchWay($waybills,$param['waybill_number'],'waybills.waybill_number');
//            unset($param['waybill_number']);
//        }
//        if($param['source_bill'] ?? false) {// 上游单号
//            $this->searchWay($waybills,$param['source_bill'],'waybills.source_bill');
//            unset($param['source_bill']);
//        }
//        if($param['wms_bill_number']?? false){ // wms单号
//            $this->searchWay($waybills,$param['wms_bill_number'],'waybills.wms_bill_number');
//            unset($param['wms_bill_number']);
//        }
        $columnQueryRules=[
            'waybill_number' => ['batch' => ''],
            'carrier_bill' => ['batch' => ''],
            'wms_bill_number' => ['batch' => ''],
            'origination' => ['batch' => ''],
            'source_bill' => ['batch' => ''],
            'car_owner_info' => ['batch' => ''],
            'created_at_start' => ['alias' => 'created_at' , 'startDate' => ':00'],
            'created_at_end' => ['alias' => 'created_at' , 'endDate' => ':59'],
            'updated_at_start' => ['alias' => 'updated_at' , 'startDate' => ':00'],
            'updated_at_end' => ['alias' => 'updated_at' , 'endDate' => ':59'],
            'deliver_at_start' => ['alias' => 'deliver_at' , 'startDate' => ':00'],
            'deliver_at_end' => ['alias' => 'deliver_at' , 'endDate' => ':59'],
            'uriType' => ['alias' => 'type'],
            'id' => ['multi' => ','],
            'logistic_id' => ['multi' => ','],
            'mileage' => ['like' => ''],
            'carrier_weight_other' => ['like' => ''],
        ];
        $waybills = app(QueryService::class)->query($param,$waybills,$columnQueryRules,"waybills");
        return $waybills;
    }

    public function paginate(array $param){
        $waybills = $this->conditionQuery($param);
        return $waybills->paginate($param['paginate'] ?? 50);
    }

    public function get(array $param){
        $waybills = $this->conditionQuery($param);
        return $waybills->get();
    }
    public function dailyBilling(array $param){
        $waybills = Waybill::query()->with(['owner','logistic','originationCity','destinationCity.parent',
            'uploadFile','amountUnit','warehouseWeightUnit','carrierWeightUnit','district','order',
            'warehouseWeightUnitOther','carrierWeightUnitOther','carType','uploadFile','waybillAuditLogs.user'])
            ->selectRaw('waybills.* ,waybill_on_tops.id top_id,waybill_on_tops.remark,waybill_on_tops.updated_at top_update')
            ->leftJoin('waybill_on_tops','waybill_on_tops.waybill_id','=','waybills.id')
            ->whereNull('waybill_on_tops.deleted_at')
            ->orderBy('waybill_on_tops.updated_at','desc')
            ->orderBy('waybills.id','desc')
            ->where('waybills.created_at','like',$param['screenDate'].'%')
            ->where('waybills.type','专线')
            ->get();
        foreach ($waybills as $waybill){
            if (!$waybill['carrier_weight_other'] && !$waybill['carrier_weight']) return null;
            if (!$waybill['carrier_weight_other']) $waybill['carrier_weight_other']=floor($waybill['carrier_weight']/0.4);
        }
        $daily_total_weight=$waybills->sum('carrier_weight_other');
        $updateParams = [['id','pick_up_fee','updated_at']];
        foreach ($waybills as $waybill){
            $waybill['pick_up_fee']=floor(($waybill->carrier_weight_other/$daily_total_weight)*$param['billing']);
            $updateParams[] = [
                'id' => $waybill->id,
                'pick_up_fee' => floor(($waybill->carrier_weight_other/$daily_total_weight)*$param['billing']),
                'updated_at' => Carbon::now()->toDateTimeString(),
            ];
        }
        if (count($updateParams)>0)app(BatchUpdateService::class)->batchUpdate('waybills', $updateParams);
        return $waybills;

    }

    public function store(Request $request){
        return DB::transaction(function ()use($request){
            $waybill=new Waybill();
            $inputs = $request->all();
            $inputs['status']='未审核';
            $inputs['waybill_number']=Uuid::uuid1();
            $waybill->fill($inputs);
            if ($request->collect_fee)$waybill->collect_fee=$request->collect_fee;
            $waybill->save();
            $number_id=$waybill->id;
            if ($request->type=='直发车') $waybill_number='BSZF';
            else $waybill_number='BSZX';
            $waybill_number .= date ("ymd").str_pad($number_id>99999?$number_id%99999:$number_id,4,"0",STR_PAD_LEFT);
            $waybill->update(['waybill_number' => $waybill_number ]);
            WaybillAuditLog::query()->create([
                'waybill_id'=>$waybill->id,
                'audit_stage'=>'创建',
                'user_id'=>Auth::id() ?? 0,
            ]);
            return $waybill;
        });
    }

    public function find($id){
        return Waybill::query()->find($id);
    }

    public function update(Request $request,$id)
    {
        $waybill = $this->find($id);
        //替换换行符
        if ($request->dispatch_remark) {
            $request->offsetSet('dispatch_remark', str_replace(["\n","\r"], ' ', $request->dispatch_remark));
        }
        if (!$request->destination) $request->offsetSet('destination', $waybill->destination);
        $waybill->fill($request->input());
        $waybill->update();
        return $waybill;
    }

    public function getDeliveringSql(array $param){
        $waybills = $this->conditionQuery($param);
        if (!Auth::user()->isSuperAdmin()){
            $users=DB::table('logistic_user')->where('user_id',Auth::id())->get();
            $userIds=array_column($users->toArray(),'logistic_id');
            $waybills=$waybills->whereIn("waybills.logistic_id",$userIds);
        }
        return $waybills->leftJoin('owners','owners.id','=','waybills.owner_id')->selectRaw('owners.name owner_name')
            ->leftJoin('logistics','logistics.id','=','waybills.logistic_id')
            ->selectRaw('logistics.name carrier_name')
            ->sql();
    }

    public function createInstantBill(Waybill $waybill) :bool
    {
        /** @var \stdClass $waybill */
        if (!$waybill || $waybill->status != "已完结" || !$waybill->wms_bill_number || !$waybill->logistic_id)return false;
        $waybill->loadMissing(["destinationCity","order.owner"]);
        if (!$waybill->destinationCity && !$waybill->order)return false;

        $owner_id = $waybill->order->owner_id ?? $waybill->owner_id;
        $detail = OwnerFeeDetail::query()->where("type","发货")
            ->where("owner_id",$owner_id)->whereIn("operation_bill",[$waybill->wms_bill_number,$waybill->waybill_number])->first();

        if ($detail && $detail->logistic_fee !== null)return false;

        if ($waybill->type == "专线"){
            /** @var OwnerPriceLogisticService $service */
            $service = app("OwnerPriceLogisticService");
            list($fee,$taxFee) = $service->matching($waybill->carrier_weight_other,$owner_id,$waybill->logistic_id,
                $waybill->carrier_weight_unit_id_other,$waybill->order ? app("RegionService")->getProvince($waybill->order->province) : $waybill->destinationCity->province_id,
                $waybill->destination_city_id);
        }else{
            /** @var OwnerPriceDirectLogisticService $service */
            $service = app("OwnerPriceDirectLogisticService");
            list($fee,$taxFee) = $service->matching($waybill->mileage,$owner_id,$waybill->carType_id);
        }

        $obj = [
            "owner_id" => $owner_id,
            "worked_at"=> $waybill->updated_at,
            "type" => "发货",
            "operation_bill" => $waybill->waybill_number,
            "province" => $waybill->order_id ? ($waybill->order->province ?? '') : ($waybill->destinationCity->parent->name ?? ''),
            "consignee_name" => $waybill->recipient,
            "consignee_phone" => $waybill->recipient_mobile,
            "commodity_amount" => $waybill->amount,
            "logistic_bill" => $waybill->carrier_bill,
            "volume" =>$waybill->carrier_weight ?? $waybill->warehouse_weight,
            "weight" => $waybill->carrier_weight_other ?? $waybill->warehouse_weight_other,
            "logistic_id" => $waybill->logistic_id,
            "logistic_fee" => $fee,
            "outer_id" => $waybill->id,
            "outer_table_name" => "waybills",
            "logistic_tax_fee" => $taxFee,
        ];
        if ($detail)app("OwnerFeeDetailService")->updateFind($detail,$obj);
        else OwnerFeeDetail::query()->create($obj);
        return true;
    }
}
