<?php


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


use App\Events\WeighedEvent;
use App\Jobs\WeightUpdateInstantBill;
use App\MeasuringMachine;
use App\OracleActAllocationDetails;
use App\OracleDOCOrderHeader;
use App\OrderPackage;
use App\Services\OrderService;
use Illuminate\Support\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;

class WeightBaseController
{

    protected $weight = '';     // 重量
    protected $length = '';     // 长
    protected $width = '';      // 宽
    protected $height = '';     // 高
    protected $code = '';       // 快递单号
    protected $weight_at = '';  // 称重时间
    protected $hid = '';        // 称重设备id
    protected $name = '';       // 名称

    public function new(Request $request)
    {
//        app('LogService')->log(__METHOD__, $this->name, "记录上传日志：" . json_encode($request->all()) . '||' , null);
        $errors = $this->validator($request);
        if(count($errors)){
            app('LogService')->log(__METHOD__, $this->name, "上传校验Error：" . json_encode($request->all()) , null);
            return $this->validatorErrors($errors);
        }
        return $this->weightOrderPackage($request);
    }

    public function weightOrderPackage(Request $request)
    {
        /**
         * @var OrderPackage $orderPackage
         * @var MeasuringMachine $measuringMachine
         */
        // 1、转化数据
        $params = $this->conversionRequest($request);

        // 2.获取快递单号
        $logistic_number = $this->getCodeValue($params);
        if(!$logistic_number)return $this->getLogisticNumberIsNullMessage($params);
        // 3、获取称重设备
        $measuringMachine = $this->getMeasuringMachine($params);

        // 4、快递单号对应的OrderPackage
        $orderPackage = $this->getOrderPackageByCode($logistic_number);
        if (is_null($orderPackage)) {
            /** @var OracleDOCOrderHeader $orderHeader */
            $orderHeader = $this->findOrderHeaderByLogisticNumber($logistic_number);
            if (is_null($orderHeader)) {
                app('LogService')->log(__METHOD__, $this->name, 'WMSOrderHeaderNotFind (Error)',$logistic_number , null);
                return $this->getNotFindOrderHeaderMessage($params, $orderPackage);
            }
            try {
                $order = $this->createOrderByOrderHeader($orderHeader);
                $orderPackage = $this->createOrderPackage($params, $measuringMachine, $order);
            } catch (\Exception $e) {
                app('LogService')->log(__METHOD__, $this->name, '写入WAS失败! (Error)',$logistic_number , null);
                return json_encode(["success" => false, "message" => "写入WAS失败!"], JSON_UNESCAPED_UNICODE);
            }
        }

        // 5、更新包裹信息
        $bool = $this->updateOrderPackage($orderPackage, $params, $measuringMachine);
        // 6、称重时间
        if($bool)$this->afterApply($orderPackage);
        else {
            app('LogService')->log(__METHOD__, $this->name, '写入WAS失败! (Error)',$logistic_number , null);
            return $this->getUpdatePackageMessage($orderPackage);
        }

        // 7、处理波次信息 推送至WMS称重信息
        try {
            $this->activityWaveNoProcessing($orderPackage);
        } catch (\Exception $e) {
            app('LogService')->log(__METHOD__, $this->name, 'weightApi (Error)', json_encode($orderPackage) . '||' . json_encode($e), null);
            return $this->getWeightMessage($orderPackage, $e);
        }

        $response = $this->getSuccessMessage($params, $orderPackage);
        app('LogService')->log(__METHOD__, $this->name, "下发写入包裹成功：" . json_encode($request->getContent()) . '||' . json_encode($response), null);
        return json_encode($response, JSON_UNESCAPED_UNICODE);
    }

// region ---数据转化

    public function conversionRequest(Request  $request)
    {
        //  1、转化数据
        $params = [];
        foreach ($request->input() as $key => $item) {
            $params[strtolower($key)] = $item;
        }
        return $params;
    }
// endregion


//  region ---称重完成之后的操作
    // 后续操作
    public function afterApply(OrderPackage $orderPackage)
    {
        $orderPackage->loadMissing(['order' => function ($query) {
            $query->with('owner', 'logistic');
        }, 'measuringMachine', 'paperBox']);
        event(new WeighedEvent($orderPackage));
        dispatch(new WeightUpdateInstantBill($orderPackage));
    }
// endregion

// region ---消息返回

    // 返回称重成功信息
    public function getSuccessMessage($params, $orderPackage): array
    {
        return ['success' => true, 'message' => '称重成功'];
    }

    // 返回包裹未找到异常
    public function getNotFindOrderPackageMessage($params, $orderPackage): string
    {
        return json_encode(['success' => false, 'message' => '未找打包裹信息', JSON_UNESCAPED_UNICODE]);
    }

    // 返回富勒信息未找到异常
    public function getNotFindOrderHeaderMessage($params, $orderPackage): string
    {
        return json_encode(['success' => false, 'message' => '富勒信息未找到'], JSON_UNESCAPED_UNICODE);
    }

    // 返回称重下发错误
    public function getWeightMessage($orderPackage, $e)
    {
        return json_encode(['success' => false, 'message' => $e->getMessage], JSON_UNESCAPED_UNICODE);
    }

    public function getUpdatePackageMessage($orderPackage)
    {
        return json_encode(['success' => false, 'message' => '更新包裹信息出现异常'], JSON_UNESCAPED_UNICODE);
    }

    public function getLogisticNumberIsNullMessage($params)
    {
        return json_encode(['success'=>false,'message'=>'快递单号过滤后为空'],JSON_UNESCAPED_UNICODE);    }

// endregion

//  region  ---参数校验

    public function validator(Request $request): array
    {
        return [];
    }

    public function validatorErrors($errors)
    {
        return json_encode(['success' => false, 'message' => '更新包裹信息出现异常'.json_encode($errors)],JSON_UNESCAPED_UNICODE);
    }

// endregion

// region  ---参数获取
    // 重量
    public function  getWeightValue($params)
    {
        return $this->getValue($this->weight, $params);
    }

    // 高
    public function getHeightValue($params)
    {
        return $this->getValue($this->height, $params);
    }

    // 长
    public function getLengthValue($params)
    {
        return $this->getValue($this->length, $params);
    }

    // 宽
    public function getWidthValue($params)
    {
        return $this->getValue($this->width, $params);
    }

    // 快递单号
    public function getCodeValue($params)
    {
        return $this->getValue($this->code, $params);
    }

    // 称重时间
    public function getWeightAtValue($params)
    {
        return $this->getValue($this->weight_at, $params);
    }

    // 获取参数
    public function getValue($name, $param)
    {
        $names = explode(',', $name);
        $value = array_reduce($names, function ($data, $key) {
            if (isset($data[$key])) $data = $data[$key];
            else $data = [];
            return $data;
        }, $param);
        if (is_array($value) && count($value) == 0) return null;
        return $value;
    }

    // 排序参数
    public function getEdges($params): array
    {
        $length = $this->getLengthValue($params);
        $height = $this->getHeightValue($params);
        $width = $this->getWidthValue($params);
        $edges = [$length ?? 0, $width ?? 0, $height ?? 0];
        rsort($edges);
        return $edges;
    }


// endregion

//  region ---包裹

    // 获取包裹
    public function getOrderPackageByCode($code)
    {
        return OrderPackage::query()
            ->with(['order' => function ($query) {
                /** @var Builder $query */
                $query->with('owner', 'logistic');
            }])->where('logistic_number', $code)->first();
    }

    // 更新包裹
    public function updateOrderPackage(OrderPackage $orderPackage, $params, $measuringMachine): bool
    {
        $edges = $this->getEdges($params);
        $req_date = Carbon::now()->toDateTimeString();
        $orderPackage['weight'] = $this->getWeightValue($params);
        $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;
        return $orderPackage->save();
    }

    // 创建包裹信息
    public function createOrderPackage($params, $measuringMachine, $order)
    {
        $weighed_at = Carbon::now();
        $edges = $this->getEdges($params);
        OrderPackage::query()->create([
            'order_id' => $order->id,
            'logistic_number' => $this->getCodeValue($params),
            'measuring_machine_id' => $measuringMachine->id,
            'weight' => $this->getWeightValue($params),
            'length' => $edges[0],
            'width' => $edges[1],
            'height' => $edges[2],
            'bulk' => $edges[0] * $edges[1] * $edges[2],
            'weighed_at' => $weighed_at,
            'status' => "无",
        ]);
        return $this->getOrderPackageByCode($this->getCodeValue($params));
    }

//  endregion

//  region ---称重设备
    // 获取称重设备
    public function getMeasuringMachine($params): MeasuringMachine
    {
        $hid = $this->getValue($this->hid, $params);
        /** @var MeasuringMachine $measuringMachine */
        $measuringMachine = MeasuringMachine::query()->firstOrCreate(['code' => $hid],['name' => $hid]); // 称重设备
        $measuringMachine->turnOn();
        $measuringMachine->turnOffInMinutes(30);
        return $measuringMachine;
    }
//  endregion

// region ---wms操作
    // 获取orderHeader
    public function findOrderHeaderByLogisticNumber($code)
    {
        $query = OracleActAllocationDetails::query()->select('OrderNO')->where('PickToTraceId', $code);
        $orderHeader =  OracleDOCOrderHeader::query()->with('actAllocationDetails', 'oracleBASCode')->whereIn('OrderNO', $query)->first();
        if($orderHeader == null){
            $orderHeader = OracleDOCOrderHeader::query()->with('actAllocationDetails', 'oracleBASCode')->where('SOReference5', $code)->first();
        }
        return $orderHeader;
    }

    // 根据WMS订单信息创建订单信息
    public function createOrderByOrderHeader($orderHeader)
    {
        /** @var OrderService $orderService */
        $orderService = app('OrderService');
        $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__, $this->name, ' 创建Order', json_encode($order) . " || " . $orderHeader);
        return $order;
    }

    //处理活动波次
    public function activityWaveNoProcessing(&$orderPackage)
    {
        $fluxController = new \App\Http\Controllers\api\thirdPart\flux\PackageController();
        if ($orderPackage->isActivityBatch()) {
            app('LogService')->log(__METHOD__, $this->name . " 依波次号同步所有包裹：", json_encode($orderPackage), null);
            OrderPackage::query()->where('batch_number', $orderPackage['batch_number'])->update([
                '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,
            ]);
            $result = $fluxController->markWMSOnBatch($orderPackage['batch_number'], $orderPackage['weight']);
            if (!$result['result']) {
                $orderPackage->uploaded_to_wms = "异常";
            }
        } else {
            app('LogService')->log(__METHOD__, $this->name . " 写入包裹至WMS异常：", json_encode($orderPackage), null);
            try {
                $result = $fluxController->accomplishToWMS($orderPackage);
                if ($result['result'] == 'success') $orderPackage->uploaded_to_wms = "是";
                else $orderPackage->uploaded_to_wms = "异常";
            } catch (\Exception $e) {
                $orderPackage->uploaded_to_wms = "否";
            }
        }
        $orderPackage->save();
    }
// endregion

// region ---上传快递单号处理

    /**
     * 快递单号处理
     *
     * @param $code
     * @return string
     */
    public function processCode($code): string
    {

        /** 如果是$code 是数组处理 */
        if(is_array($code)){
            return $this->processCodeArr($code);
        }
        return $this->processCodeStr($code);
    }

    /**
     *  快递单号 array 处理
     *
     * @param array $code
     * @return mixed|string
     */
    public function processCodeArr(array $code): string
    {
        usort($code,function($codeA,$codeB){
            if(strlen($codeA) == strlen($codeB))return 0;
            return strlen($codeA) > strlen($codeB) ? 1 : -1;
        });
        return $code[0];
    }

    /**
     * 快递单号 string 处理
     *
     * @param $code
     * @return string|null
     */
    public function processCodeStr($code): ?string
    {
        $codes = [];
        preg_match_all('/[\w]+/',$code,$codes);
        if(count($codes) == 0)return $code;
        $codes = array_unique(array_filter(array_shift($codes),function($item){
            return strlen($item) > 8;
        }));
        usort($codes,function($a,$b){
            if(strlen($a) == strlen($b))return 0;
            return strlen($a) < strlen($b) ? 1 : -1;
        });
        return $codes[0] ?? null;
    }

// endregion
}
