<?php


namespace App\Http\Controllers\api\thirdPart\goodscan;

use App\Events\WeighedEvent;
use App\Http\Controllers\LogisticNumberFeatureController;
use App\Jobs\WeightUpdateInstantBill;
use App\MeasuringMachine;
use App\OracleDOCOrderHeader;
use App\Order;
use App\OrderPackage;
use App\Services\LogService;
use App\Services\OrderService;
use App\Waybill;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

class PackageController
{
    public function new_(Request $request)
    {
        app('LogService')->log(__METHOD__,'GoodScan weightApi add'.__FUNCTION__,json_encode($request->getContent()));
        $requestInput = [];
        foreach ($request->input() as $key=>$item) {
            $requestInput[strtolower($key)] = $item;
        }

        $errors = $this->validatorWeight($requestInput)->errors(); // 参数校验
        $weight = $requestInput['weight']??'';
        if($weight == '-9.9'){   // 称重异常校验
            app('LogService')->log(__METHOD__,'GoodScan weightApi (Error)'.__FUNCTION__,'异方接口称重伤上传异常[异常值为-9.9，电子秤故障或未连接]'.json_encode($request->getContent()));
            return json_encode(['code'=>500,'error'=>'weight=-9.9']);
        }
        if(count($errors) > 0){
            app('LogService')->log(__METHOD__,'error'.__FUNCTION__,json_encode($request->getContent()).'||'.json_encode($errors),null);
            return json_encode(['code'=>500,'error'=>$errors]);
        }

        /**
         * @var MeasuringMachine $measuringMachine
         * @var OrderPackage $orderPackage
         * @var OracleDOCOrderHeader $orderHeader
         * @var Order $order
         */

        $measuringMachine = $this->getMeasuringMachine($requestInput['hid']); // 返回设备并启动
        $orderPackage=$this->getOrderPackageByLogisticNumber($requestInput['code']); // 查询WAS是否有对应的包裹信息
        if($orderPackage){
            $result = $this->updateOrderPackage($orderPackage,$requestInput,$measuringMachine); // 更新包裹信息
            if($result){
                return json_encode($result);
            }
        }else{
            try {
                $orderHeader = $this->findOrderHeaderByLogisticNumber($requestInput['code']);// 查询WMS是否有对应的包裹信息
                if (!$orderHeader) {
                    return json_encode(['code' => 500, 'error' => '保存时发生错误（未在WMS中找到订单）!'], JSON_UNESCAPED_UNICODE);
                }
                $order = $this->createOrderByOrderHeader($orderHeader);
                $orderPackage = $this->getOrderPackage($requestInput, $measuringMachine, $order);// 返回包裹对象
                $this->syncOrderPackageLogistic($orderPackage);// 同步包裹订单的承运商
            } catch (\Exception $e) {
                app('LogService')->log(__METHOD__,__FUNCTION__,'GoodScan weightApi (Error)'.json_encode($request->getContent()).'||'.json_encode($orderPackage),null);
                return json_encode(["code"=>500,"error"=>"写入WMS失败!"],JSON_UNESCAPED_UNICODE);
            }
        }
        if(!empty($orderPackage->order)){
            Waybill::setWeightByOrderCode($orderPackage->order->code,$orderPackage->weight);
        }
        $orderPackage->loadMissing('measuringMachine');
        event(new WeighedEvent($orderPackage));
        dispatch(new WeightUpdateInstantBill($orderPackage));
        $response=["code"=>0,'error'=>'upload success'];
        app('LogService')->log(__METHOD__,__FUNCTION__,"异方下发写入包裹成功：".json_encode($request->getContent()).'||'.json_encode($response),null);

        return json_encode($response,JSON_UNESCAPED_UNICODE);
    }

    /**
     * @param string $hid
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model
     */
    public function getMeasuringMachine($hid)
    {
        /** @var MeasuringMachine $measuringMachine */
        $measuringMachine = MeasuringMachine::query()->firstOrCreate(['code'=>$hid]); // 称重设备
        $measuringMachine->turnOn();
        $measuringMachine->turnOffInMinutes(30);
        return $measuringMachine;
    }

    public function validatorWeight(array $request)
    {
        return Validator::make($request, [
            'code' => ['required', 'max:191'],
            'l' => ['required', 'numeric', 'min:0'],
            'w' => ['required', 'numeric', 'min:0'],
            'h' => ['required', 'numeric', 'min:0'],
            'weight' => ['required', 'numeric', 'min:0'],
            'hid' => ['required', 'string', 'min:0'],
            'picture' => ['nullable'],
        ], [
            'required' => ':attribute 为必填项',
            'max' => ':attribute 字符过多或数值过大',
            'min' => ':attribute 不得为负',
            'numeric' => ':attribute 应为数字',
            'string' => ':attribute 应为字符串',
        ], []);
    }

    /**
     * @param OrderPackage $orderPackage
     * @param array $params
     * @param MeasuringMachine $measuringMachine
     * @return array
     */
    public function updateOrderPackage(&$orderPackage,$params,$measuringMachine) //更新包裹信息 前往处理活动波次
    {
        $edges=$this->getEdges($params);

        $req_date=\Illuminate\Support\Carbon::now()->format(\Illuminate\Support\Carbon::DEFAULT_TO_STRING_FORMAT);
        $orderPackage->weight=$params['weight'];
        $orderPackage->measuring_machine_id=$measuringMachine->id;
        $orderPackage->length=$edges[0];
        $orderPackage->width=$edges[1];
        $orderPackage->height=$edges[2];
        $orderPackage->weighed_at=$req_date;
        $orderPackage->bulk=$edges[0]*$edges[1]*$edges[2]/1000;
        if($orderPackage->isActivityBatch()){
            $response=$this->activityWaveNoProcessing($orderPackage);
            if($response)return $response;
        }
        $orderPackage->save();
        return[];
    }

    /**
     * @param OrderPackage $orderPackage
     * @return array
     */
    public function activityWaveNoProcessing(&$orderPackage) //处理活动波次
    {
        $fluxController = new \App\Http\Controllers\api\thirdPart\flux\PackageController();
        if($orderPackage->isActivityBatch()){
            app('LogService')->log(__METHOD__,__FUNCTION__,"依波次号同步所有包裹：".json_encode($orderPackage),null);
            $params = [
                'weight'=>$orderPackage['weight'] ?? null,
                'length'=>$orderPackage['length'] ?? null,
                'width'=>$orderPackage['width'] ?? null,
                'height'=>$orderPackage['height'] ?? null,
                'bulk'=>$orderPackage['bulk'] ?? null,
                'measuring_machine_id'=>$orderPackage['measuring_machine_id'] ?? null,
                'weighed_at'=>$orderPackage['weighed_at'] ?? null,
                'paper_box_id'=>$orderPackage['paper_box_id'] ?? null,
            ];
            OrderPackage::query()->where('batch_number',$orderPackage['batch_number'])->update($params);
            $result=$fluxController->markWMSOnBatch($orderPackage['batch_number'], $orderPackage['weight']);
            if(!$result['result']){
                $orderPackage->uploaded_to_wms="异常";
            }
        }else{
            app('LogService')->log(__METHOD__,__FUNCTION__,"GoodScan 写入包裹至WMS：".json_encode($orderPackage),null);
            try{
                $result=$fluxController->accomplishToWMS($orderPackage);
                if ($result['result'])
                    $orderPackage->uploaded_to_wms="是";
                else
                    $orderPackage->uploaded_to_wms="异常";
            }catch (\Exception $e){
                $orderPackage->uploaded_to_wms="否";
            }
        }
        $response=$this->saveOrderPackage($orderPackage);
        return $response??[];
    }

    /**
     * @param OrderPackage $orderPackage
     * @return array
     */
    public function saveOrderPackage(&$orderPackage) //保存修改并
    {
        try {
            $logisticNumberController = new LogisticNumberFeatureController();
            if (!$orderPackage->order) {
                $orderPackage->order = new Order();
            }
            if (!$orderPackage->order->logistic) {
                $orderPackage->order->logistic = $logisticNumberController->getLogisticByFeatures($orderPackage->logistic_number);
            }
            $orderPackage->save();
            return [];
        } catch (\Exception $e) {
            $response=["msg"=>'称重下发修改时发生错误!',json_encode($e),'code'=>500,'data'=>null];
            app('LogService')->log(__METHOD__,'GoodScan weightApi (Error)'.__FUNCTION__,json_encode($orderPackage).'||'.json_encode($e),null);
            return $response;
        }
    }

    /**
     * @param string $logisticNumber
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|object|null
     */
    public function getOrderPackageByLogisticNumber($logisticNumber)
    {
        return OrderPackage::query()
            ->with(['order'=>function($query){
                $query->with('owner','logistic');
            }])
            ->where('logistic_number',$logisticNumber)
            ->first();
    }

    /**
     * @param string $logisticNumber
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|object|null
     */
    public function findOrderHeaderByLogisticNumber($logisticNumber)
    {
        return OracleDOCOrderHeader::query()->with('actAllocationDetails','oracleBASCode')
            ->whereHas('actAllocationDetails',function($query)use($logisticNumber){
                $query->where('picktotraceid',$logisticNumber);
            })
//            ->orWhere('soreference5',$logisticNumber)
            ->first();
    }

    /**
     * @param OracleDOCOrderHeader $orderHeader
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model
     */
    public function createOrderByOrderHeader($orderHeader)
    {
        /** @var OrderService $orderService */
        $orderService=app(OrderService::class);
        $order_create_params=$orderService->getParamByOrderHeader($orderHeader);
        $order = $orderService->first(['code'=>$orderHeader->orderno]);
        if($order)return $order;
        $order = $orderService->createOrder($order_create_params);
        app('LogService')->log(__METHOD__,__FUNCTION__,'GoodScan 创建Order',json_encode($order)." || ".$orderHeader);
        return $order;
    }

    /**
     * @param array $requestInput
     * @param MeasuringMachine $measuringMachine
     * @param Order $order
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|object|null
     */
    public function getOrderPackage($requestInput,$measuringMachine,$order)
    {
//        $weighed_at =$requestInput['time']??Carbon::now();
        $weighed_at =Carbon::now();
        $edges=$this->getEdges($requestInput);
        OrderPackage::query()->create([
            'order_id'=>$order->id,
            'logistic_number'=>$requestInput['code'],
            'measuring_machine_id'=>$measuringMachine->id,
            'weight'=>$requestInput['weight'],
            'length'=>$edges[0],
            'width'=>$edges[1],
            'height'=>$edges[2],
            'bulk'=>$edges[0]*$edges[1]*$edges[2],
            'weighed_at'=>$weighed_at,
            'status'=>"无",
        ]);
        return $this->getOrderPackageByLogisticNumber($requestInput['code']);
    }

    /**
     * @param array $requestInput
     * @return array
     */
    public function getEdges($requestInput)
    {
        $edges = [$requestInput['l']??0,$requestInput['w']??0,$requestInput['h']??0];
        rsort($edges);
        return $edges;
    }

    /**
     * @param $orderPackage
     */
    public function syncOrderPackageLogistic(&$orderPackage) // 同步订单承运商
    {
        $logisticNumberController = new LogisticNumberFeatureController();
        if (!$orderPackage->order) {
            $orderPackage->order = new Order();
        }
        if (!$orderPackage->order->logistic) {
            $orderPackage->order->logistic = $logisticNumberController->getLogisticByFeatures($orderPackage->logistic_number);
        }
        $orderPackage->save();
    }

}
