<?php

namespace App\Services;

use App\Logistic;
use App\OracleActAllocationDetails;
use App\OracleDOCOrderDetail;
use App\OracleDOCOrderHeader;
use App\Order;
use App\OrderPackage;
use App\OrderPackageCommodities;
use App\OrderTracking;
use App\Services\common\BatchUpdateService;
use App\Services\common\DataHandlerService;
use Carbon\Carbon;
use App\Traits\ServiceAppAop;


class OrderPackageService
{
    use ServiceAppAop;
    protected $modelClass=OrderPackage::class;
    public function batchUpdate(array $params){
        return app(BatchUpdateService::class)->batchUpdate('order_packages',$params);
    }


    /**
     * @param string $logistic_number
     * @param array $values
     * @return OrderPackage $package
     */
    public function firstOrCreate($logistic_number, array $values){
        /** @var $package OrderPackage  */
        $package = OrderPackage::query()->where('logistic_number',$logistic_number)->first();
        if ($package)return $package;

        /** @var OrderService */
        $order = app('OrderService')->logisticNumberFirstOrCreateOrder($logistic_number);
        if ($order) $values["order_id"] = $order->id;

        $values["logistic_number"] = $logistic_number;
        /** @var OrderPackage $package */
        $package = OrderPackage::query()->create($values);
        return $package;
    }

    public function createExceptionPaginate($paginate)
    {
        return OrderPackage::query()->select('id', 'status', 'logistic_number', 'measuring_machine_id', 'weighed_at', 'weight', 'length', 'width', 'height', 'bulk', 'paper_box_id')
            ->where('status', '上传异常')->orWhere('status', '测量异常')->orderBy('created_at', 'DESC')
            ->paginate($paginate);
    }

    public function issueExceptionPaginate($paginate)
    {
        return OrderPackage::query()->select('id', 'logistic_number', 'created_at', 'batch_number', 'batch_rule')
            ->where('status', '下发异常')->orWhere('status', '记录异常')
            ->orWhere('uploaded_to_wms', '异常')->orderBy('created_at', 'DESC')
            ->paginate($paginate);
    }

    public function getByWmsOrders($orderHeaders){
        $order_nos = data_get($orderHeaders,'*.orderno');
        return OrderPackage::query()->with('order')
            ->whereIn('order_id',function($query) use ($order_nos){
                $query->from('orders')->select('id')->whereIn('code',$order_nos);
            })->get();
    }

    public function create(array $params)
    {
        if(count($params) == 0)return null;
        try {
            $this->insert($params);
            app('LogService')->log(__METHOD__,__FUNCTION__,'批量生成 orderPackage' . count($params) . json_encode($params));
        } catch (\Exception $e) {
            app('LogService')->log(__METHOD__,__FUNCTION__,'批量生成 orderPackage error ' . json_encode($params) . $e->getMessage() . $e->getTraceAsString());
        } finally {
            $logistic_numbers = data_get($params,'*.logistic_number');
            unset($params);
            return OrderPackage::query()->whereIn('logistic_number',$logistic_numbers)->get();
        }
    }

    public function getByOrderNos($orderNos)
    {
        return OrderPackage::query()->with('order')
            ->whereIn('order_id',function($query)use($orderNos){
                $query->from('orders')->select('id')->whereIn('code',$orderNos);
            })->get();
    }

    public function update($orderClientNo,$logisticNumber)
    {
        $order = Order::query()->with('packages.commodities.commodity')->where('client_code',$orderClientNo)->first();
        if(!$order){
            $order = Order::query()->create(['client_code'=>$orderClientNo]);
        }
        $orderPackage = OrderPackage::query()->where('logistic_number',$logisticNumber)->first();
        if($orderPackage){return  compact('orderPackage','order');}
        $orderPackage = OrderPackage::query()->create(['order_id'=>$order->id,'logistic_number'=>$logisticNumber]);
        return  compact('orderPackage','order');
    }

    public function syncOrderPackage(&$orderHeaders)
    {
        $this->syncPackageByOrderHeaders($orderHeaders);
    }

    public function syncPackageByOrderHeaders(&$orderHeaders)
    {
        /** @var OrderService $orderService */
        $orderService = app('OrderService');
        if(!$orderHeaders)return;
        $orders = $orderService->getByWmsOrders($orderHeaders);
        $packages = $this->getByOrderNos(data_get($orderHeaders,'*.orderno'));          // 已有
        $this->createOrderPackage($orderHeaders,$orders,$packages);                     // 创建package
        $this->updatePackage($orderHeaders,$packages);
        $this->deleteUnnecessaryPackage($orderHeaders,$packages);     // 删除package
        unset($orders,$packages);       // 手动清除
    }

    public function createOrderPackage($orderHeaders,$orders,$packages)
    {
        if(!$orderHeaders)return;
        /**
         * @var DataHandlerService $dataHandlerService
         * @var LogisticService $logsitcService
         */
        $logisticService = app(LogisticService::class);
        $dataHandlerService = app(DataHandlerService::class);
        $orderHeaders_map = $dataHandlerService->dataHeader(['orderno'],$orderHeaders);
        $packages_maps = $dataHandlerService->dataHeader(['logistic_number'],$packages);
        $inner_params = [];

        /** 定制京东快递的订单 */
        $logistic = $logisticService->getLogisticByCodes(['JDKD'])->first();
        foreach ($orders as $order){
            $orderHeader = $dataHandlerService->getKeyValue(['orderno'=>$order->code],$orderHeaders_map);
            if(!$orderHeader)continue;
            if($orderHeader->sotatus == 90)continue;
            $params = $this->getInnerParams($orderHeader,$order,$packages_maps,$logistic);
            $inner_params = array_merge($inner_params,$params);
        }

        /** 批量添加 */
        if(count($inner_params)>0){
            try {
                $inner_array = array_chunk($inner_params,5000);
                foreach ($inner_array as $params) {
                    $bool = $this->insert($params);
                    $bool ? LogService::log(__METHOD__, __FUNCTION__, '批量添加 OrderPackage ' . count($inner_params) . ' || ' . json_encode($inner_params)) : null;
                }
            } catch (\Exception $e) {
                LogService::log(__METHOD__, __FUNCTION__, '批量添加 OrderPackage error ' . count($inner_params) . ' || ' .json_encode($e->getMessage()). json_encode($inner_params).json_encode($e->getTraceAsString()));
            }
        }
    }

    public function getInnerParams($orderHeader,$order,$packages_maps,$logistic): array
    {
        /**
        * @var DataHandlerService $dataHandlerService
        */
        $dataHandlerService = app('DataHandlerService');
        $logistic_numbers = array_diff(array_unique(data_get($orderHeader->actAllocationDetails,'*.picktotraceid')),['','*']);
        $date = Carbon::now()->format('Y-m-d H:i:s');
        $inner_params = [];
        $sentAtMap = [];

        if($orderHeader['sostatus'] == '90'){
            if($orderHeader['soreference5']=='')$logistic_numbers = [$orderHeader['orderno']];
            else $logistic_numbers = [$orderHeader['soreference5']];
        }

        /** sent_at checktime */
        foreach ($orderHeader->actAllocationDetails as $item){
            $sentAtMap[$item->picktotraceid] = $item;
        }

        /** 承运商是京东时的定制操作 */
        if($order['id'] == $logistic['id'] && count($logistic_numbers) == 1){
            $logistic_numbers = [$orderHeader['soreference5']];
            $sentAtMap[$orderHeader['soreference5']] = $orderHeader->actAllocationDetails->first() ?? null;
        }

        foreach ($logistic_numbers as $logistic_number){
            $package = $dataHandlerService->getKeyValue(['logistic_number'=>$logistic_number],$packages_maps);

            if(isset($package))continue;
            try {
                $data = $sentAtMap[$logistic_number];
            } catch (\Exception $e) {
                $data = null;
            }

            $inner_params[] = [
                'order_id' => $order->id,
                'logistic_number' => $logistic_number,
                'created_at' => $date,
                'updated_at' => $date,
                'status' => '无',
                'owner_id' => $order->owner_id,
                'sent_at' => $data ? $data->checktime:null,
            ];
        }
        return $inner_params;
    }


    public function deleteUnnecessaryPackage($orderHeaders,$packages)
    {
        /**
         * @var DataHandlerService $dataHandlerService
         * @var OrderTrackingService $orderTrackingService
         * @var OrderPackageCommoditiesService $orderPackageCommoditiesService
         */
        $dataHandlerService = app(DataHandlerService::class);
        $orderPackageCommoditiesService = app('OrderPackageCommoditiesService');

        /** 获取所有的 picktotraceid WMS快递单号*/
        $logistic_numbers = data_get($orderHeaders,'*.actAllocationDetails.*.picktotraceid');

         /** WMS定制化操作 订单取消 和 京东快递*/
        foreach ($orderHeaders as $orderHeader) {
            if($orderHeader['sostatus'] == '90'){
                if($orderHeader['soreference5']=='')$logistic_numbers[] =$orderHeader['orderno'];
                else $logistic_numbers[] = $orderHeader['soreference5'];
            }
            if($orderHeader['userdefine1'] == 'JDKD'){
                $logistic_numbers[] = $orderHeader['soreference5'];
            }
        }

        /** WMS快递单号唯一化 剔除 '',' ','*'*/
        $logistic_numbers = array_unique(array_values($logistic_numbers));
        $logistic_numbers = array_diff($logistic_numbers,['',' ','*']);

        /** WAS数据库中已有的快递单号*/
        $packages_maps = $dataHandlerService->dataHeader(['logistic_number'],$packages);
        $exits_number = data_get($packages,'*.logistic_number');

        /** WMS快递单号 和 WAS的快递单号 的差集*/
        $packages = [];
        $diff_number = array_diff($exits_number,$logistic_numbers);
        /** 记录差集对应的OrderPackage的id*/
        foreach ($diff_number as $number) {
            $package = $dataHandlerService->getKeyValue(['logistic_number'=>$number],$packages_maps);
            if($package ?? false)$packages[]=$package->id;
        }

        /** 删除 OrderPackage 和 OrderPackageCommodities*/
        if(count($packages)==0)return;
        try {
            $bool = OrderPackage::query()->whereIn('id', $packages)->delete();
            $orderPackageCommodities = OrderPackageCommodities::query()->whereIn('order_package_id',$packages)->get();
            $orderPackageCommoditiesService->deleteOrderCommodities($orderPackageCommodities);
            $bool ? LogService::log(__METHOD__,__FUNCTION__,'删除多余包裹 ids:'.json_encode($packages)) : null;
        } catch (\Exception $e) {
            LogService::log(__METHOD__,__FUNCTION__,'删除多余包裹 ids:'.json_encode($packages).$e->getMessage());
        }
    }

    private function updatePackage($orderHeaders, $packages)
    {
        $map = $this->getSentAtMap($orderHeaders);
        $update_params = [];
        $update_params[] = ['id','sent_at'];
        foreach ($packages as $package) {
            if ($package->sent_at) continue;
            try {
                $checktime = $map[$package->logistic_number];
            } catch (\Exception $e) {
                continue;
            }
            if ($checktime) {
                $update_params[] = [
                    'id' => $package->id,
                    'sent_at' => $checktime,
                ];
            }else {
                continue;
            }

        }
        $this->batchUpdate($update_params);
    }

    /**
     * @param $orderHeaders
     * @return array
     */
    private function getSentAtMap($orderHeaders): array
    {
        $map = [];
        foreach ($orderHeaders as $orderHeader) {
            $actAllocationDetails = $orderHeader->actAllocationDetails;
            foreach ($actAllocationDetails as $actAllocationDetail) {
                $logistic_number = $actAllocationDetail->picktotraceid;
                $map[$logistic_number] = $actAllocationDetail->checktime;
            }
        }
        return $map;
    }

}
