<?php

namespace App\Services;

use App\Commodity;
use App\Http\Controllers\CommodityController;
use App\CommodityBarcode;
use App\OracleBasSKU;
use App\Owner;
use App\Services\common\BatchUpdateService;
use App\Services\common\DataHandlerService;
use App\ValueStore;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Cache;
use App\Traits\ServiceAppAop;


class CommodityService
{
    use ServiceAppAop;
    protected $modelClass=Commodity::class;

    /**
     * @var CacheService $cacheService
     * @var OwnerService $ownerService
     */
    private $cacheService;
    private $ownerService;

    function __construct()
    {
        $this->cacheService = app('CacheService');
        $this->ownerService = app('OwnerService');
    }

    public function firstOrCreate($param, $column = null): Commodity
    {
        if ($column) return Commodity::query()->firstOrCreate($param, $column);
        return Commodity::query()->firstOrCreate($param);
    }

    public function updateOrCreate($param, $column = null)
    {
        if ($column) return Commodity::query()->updateOrCreate($param, $column);
        return Commodity::query()->updateOrCreate($param);
    }

    public function first(array $params, $with = null)
    {
        $commodity = Commodity::query();
        if ($with) $commodity->with($with);
        foreach ($params as $column => $value) {
            if (!is_array($value)) $commodity->where($column, $value);
            else $commodity->whereIn($column, $value);
        }
        return $commodity->first();
    }

    public function get(array $params)
    {
        $query = Commodity::query()->with('barcodes');
        if ($params["owner_id"] ?? false) {
            $query->where("owner_id", $params["owner_id"]);
        }
        if ($params["sku"] ?? false) {
            if (!is_array($params["sku"])) $params["sku"] = [$params["sku"]];
            $query->whereIn('sku', $params["sku"]);
        }
        return $query->get();
    }


    public function getOwnerCommodities(array $params)
    {
        $query = Commodity::query();
        foreach ($params as $column => $value) {
            if (!is_array($value)) $query->where($column, $value);
            else $query->whereIn($column, $value);
        }
        return $query->get();
    }

    /* 批量更新 */
    public function batchUpdate(array $params)
    {
        return app(BatchUpdateService::class)->batchUpdate('commodities', $params);
    }

    /* 根据货主条形码查找商品 */
    private function ownerBarcodeSeekCommodityQuery(Builder $query, array $ownerParam, $barcode)
    {
        $query->whereHas('owner', function ($builder) use ($ownerParam) {
            foreach ($ownerParam as $column => $param) {
                $builder->where($column, $param);
            }
        });
        $query->whereHas('barcodes', function ($builder) use ($barcode) {
            if (is_array($barcode)) $builder->whereIn('code', $barcode);
            else $builder->where('code', $barcode);
        });
        // haozi  2020-12-14
//        $query->whereIn('id', function ($builder) use ($barcode) {
//            if (is_array($barcode)) $builder->from('commodity_barcodes')->select('commodity_id')->whereIn('code', $barcode);
//            else $builder->from('commodity_barcodes')->select('commodity_id')->where('code', $barcode);
//        });
        return $query;
    }

    public function ownerBarcodeSeekCommodityFirst(array $ownerParam, $barcode, $with = null)
    {
        $commodity = Commodity::query();
        if ($with) $commodity->with($with);
        $commodity = $this->ownerBarcodeSeekCommodityQuery($commodity, $ownerParam, $barcode);
        return $commodity->first();
    }

    public function ownerBarcodeSeekCommodityGet(array $ownerParam, $barcode, $isNullSku = false)
    {
        $commodities = Commodity::query()->with('barcodes');
        if ($isNullSku) $commodities->whereNull('sku');
        $commodities = $this->ownerBarcodeSeekCommodityQuery($commodities, $ownerParam, $barcode);
        return $commodities->get();
    }

    /* 通过货主代码与条形码寻找FLUX商品补充至WMS 单条*/
    public function ownerAndBarcodeFirstOrCreate(Owner $owner, $barcode)
    {
        $wmsCommodity = app('OracleBasSkuService')->first(['customerid' => $owner->code, 'barcode' => $barcode]);
        if (!$wmsCommodity) return null;

        $commodity = $this->firstOrCreate(['owner_id' => $owner->id, 'sku' => $wmsCommodity->sku], [
            "name" => $wmsCommodity->descr_c,
            "sku" => $wmsCommodity->sku,
            "owner_id" => $owner->id,
            "length" => $wmsCommodity->skulength,
            "width" => $wmsCommodity->skuwidth,
            "height" => $wmsCommodity->skuhigh,
            "volumn" => $wmsCommodity->cube,
            "pack_spec"  => $wmsCommodity->packid == 'STANDARD' ? 0 : explode("/",$wmsCommodity->packid)[1],
            "remark" => $wmsCommodity->notes,
        ]);
        if ($wmsCommodity->alternate_sku1) app('CommodityBarcodeService')->first([
            'commodity_id' => $commodity->id,
            'code' => $wmsCommodity->alternate_sku1,
        ]);
        if ($wmsCommodity->alternate_sku2) app('CommodityBarcodeService')->first([
            'commodity_id' => $commodity->id,
            'code' => $wmsCommodity->alternate_sku2,
        ]);
        return $commodity;
    }

    public function create(array $params)
    {
        return Commodity::query()->create($params);
    }

    public function getByWmsOrders($orderHeaders)
    {
        if (!$orderHeaders) return null;
        $customerId_sku_map = [];
        foreach ($orderHeaders as $orderHeader) {
            $oracleDOCOrderDetails = $orderHeader->oracleDOCOrderDetails;
            foreach ($oracleDOCOrderDetails as $oracleDOCOrderDetail) {
                $value = [
                    'owner_code' => $oracleDOCOrderDetail->customerid,
                    'sku' => $oracleDOCOrderDetail->sku
                ];
                if (!in_array($value, $customerId_sku_map)) {
                    $customerId_sku_map[] = $value;
                }
            }
        }

        $owner_codes = array_diff(array_unique(data_get($customerId_sku_map, '*.owner_code')), ['', '*', null]);
        if (!$owner_codes) return null;

        $owners = Owner::query()->whereIn('code', $owner_codes)->get();

        $owners_code_map = [];
        $owners_id_map = [];
        foreach ($owners as $owner) {
            $owners_code_map[$owner->code] = $owner;
            $owners_id_map[$owner->id] = $owner;
        }
        $orderHeader_sku = array_diff(array_unique(data_get($customerId_sku_map, '*.sku')), ['', '*', null]);
        $commodities = Commodity::query()
            ->whereIn('owner_id', data_get($owners, '*.id'))
            ->whereIn('sku', $orderHeader_sku)
            ->get();

        if ($commodities->count() < count($customerId_sku_map)) {
            $commoditiesInWAS索引_sku = [];
            foreach ($commodities as $commodityInWms) {
                $owner = $owners_id_map[$commodityInWms->owner_id] ?? '';
                if (!$owner) continue;
                $key = 'owner_cod=' . $owner['code'] . ' sku=' . $commodityInWms->sku;
                $commoditiesInWAS索引_sku[$key] = $commodityInWms;
            }
            $commodities需要新增 = [];
            foreach ($customerId_sku_map as $commodityInWms) {
                $key = 'owner_cod=' . $commodityInWms['owner_code'] . ' sku=' . $commodityInWms['sku'];
                if ($commoditiesInWAS索引_sku[$key] ?? false) continue;
                $commodities需要新增[$key] = $commodityInWms;
            }
            $commodity_set = $this->createCommodities($commodities需要新增, $owners_code_map);
            $commodities = $commodities->concat($commodity_set);
        }
        return $commodities;
    }

    public function createCommodities($params, $owners_code_map)
    {
        if (!$params) return [];
        $bas_sku_arr = OracleBasSKU::query()
            ->selectRaw('customerid,sku,descr_c,skulength,skuwidth,skuhigh,cube')
            ->whereIn('CustomerID', data_get($params, '*.owner_code'))
            ->whereIn('Sku', data_get($params, '*.sku'))
            ->get();
        $insert_params = [];
        $created_at = Carbon::now()->format('Y-m-d H:i:s');
        foreach ($bas_sku_arr as $bas_sku) {
            $owner = $owners_code_map[$bas_sku->customerid] ?? '';
            if (!$owner) continue;
            if ($bas_sku->sku == null) continue;
            if ($bas_sku->descr_c == '') continue;
            $insert_params[] = [
                'owner_id' => $owner->id,
                'sku' => $bas_sku->sku,
                'name' => $bas_sku->descr_c,
                'created_at' => $created_at,
                'length' => $bas_sku->skulength,
                'width' => $bas_sku->skuwidth,
                'height' => $bas_sku->skuhigh,
                'volumn' => $bas_sku->cube,
                "pack_spec"  => $bas_sku->packid == 'STANDARD' ? 0 : explode("/",$bas_sku->packid)[1],
                "remark" => $bas_sku->notes,
            ];
        }
        if (count($insert_params) > 0) {
            try {
                $this->insert($insert_params);
                app('LogService')->log(__METHOD__, __FUNCTION__, '批量添加 commodity ' . count($insert_params) . json_encode($insert_params));
            } catch (\Exception $e) {
                app('LogService')->log(__METHOD__, __FUNCTION__, '批量添加 commodity error' . json_encode($insert_params) . "||" . $e->getMessage() . '||' . $e->getTraceAsString());
            }
        }
        return Commodity::query()
            ->whereIn('owner_id', data_get($owners_code_map, '*.id'))
            ->whereIn('sku', data_get($params, '*.sku'))
            ->get();
    }

    public function createTemporaryCommodity(array $params)
    {
        $params["type"] = "临时";
        return Commodity::query()->create($params);
    }

    public function syncBarcodes($barcodesStr, $ownerId, $sku): Commodity
    {
        $barcodes = (function () use ($barcodesStr) {
            $barcodes = rtrim($barcodesStr, ',');
            $barcodes = explode(',', $barcodes);
            foreach ($barcodes as $k => $barcode) {
                if (!trim($barcode)) unset($barcodes[$k]);
            }
            return $barcodes;
        })();
        //
//        $commodities=$this->get_([$ownerId],[$sku],[],true);
//        if ($commodities->first()){
//            $commodity=$commodities->first();
//        }else{
        $commodity = $this->firstOrCreate(['owner_id' => $ownerId, 'sku' => $sku]);
//        }
        $commodityBarcodes = $commodity['barcodes'] ?? new Collection();


        /** @var CommodityBarcodeService $commodityBarcodeService */
        $commodityBarcodeService = app('CommodityBarcodeService');
        $redundantCommodityBarcodes = new Collection();
        foreach ($commodityBarcodes as $commodityBarcode) {//清除数组中 已经在商品有的条码，清除商品条码中，不在数组中的条码
            $hasMatch = false;
            foreach ($barcodes as $key => $barcode) {
                if ($barcodes[$key] == $commodityBarcode['code']) {
                    $hasMatch = true;
                    unset($barcodes[$key]);
                    break;
                }
            }
            if (!$hasMatch) {
                $redundantCommodityBarcodes->push($commodityBarcode);
            }
        }
        if (!empty($redundantCommodityBarcodes)) {
            $commodityBarcodeService->destroyCollections($redundantCommodityBarcodes);
        }
        if (!empty($barcodes)) {
            $commodityBarcodeService->insertMany_onCommodities([['commodity_id' => $commodity['id'], 'barcodes' => $barcodes]]);
        }
        return $commodity;
    }

    public function destroyWithOffspring(Commodity $commodity)
    {
        $barcodesIds = $commodity->barcodes->map(function ($barcode) {
            return $barcode['id'];
        });
        CommodityBarcode::destroy($barcodesIds);
        $commodity->delete();
    }

    public function syncWMSOrderCode($owner, $skus)
    {
        $basSku = OracleBasSKU::query()->whereIn('SKU', $skus)->where('CustomerID', $owner->code)->get();
        $inner_params = [];
        $created_at = new Carbon();
        $basSku->each(function ($bas_sku) use (&$inner_params, $owner, $created_at) {
            $inner_params = [
                'owner_id' => $owner->id,
                'sku' => $bas_sku->sku,
                'name' => $bas_sku->descr_c,
                'created_at' => $created_at,
                'length' => $bas_sku->skulength,
                'width' => $bas_sku->skuwidth,
                'height' => $bas_sku->skuhigh,
                'volumn' => $bas_sku->cube,
                "pack_spec"  => $bas_sku->packid == 'STANDARD' ? 0 : explode("/",$bas_sku->packid)[1],
                "remark" => $bas_sku->notes,
            ];
        });
        if (count($inner_params) > 0) {
            try {
                $this->insert($inner_params);
                app('LogService')->log(__METHOD__, __FUNCTION__, json_encode($inner_params));
            } catch (\Exception $e) {
                app('LogService')->log(__METHOD__, 'Error ' . __FUNCTION__, json_encode($inner_params) . ' || ' . $e->getMessage());
            }
        }
    }

    //获取箱规
    public function getPack($owner_id, $sku)
    {
        $that = $this;
        return app("CacheService")->getOrExecute("pack_{$owner_id}_{$sku}", function () use ($owner_id, $sku, $that) {
            $commodity = $that->first([
                "owner_id" => $owner_id,
                "sku" => $sku
            ]);
            if (!$commodity || $commodity->pack_spec === null) {
                $owner = app("OwnerService")->find($owner_id);
                $action = new CommodityController();
                $action->syncOwnerCommodities($owner->id, $owner->code, $sku);
            }
            return $that->first([
                "owner_id" => $owner_id,
                "sku" => $sku
            ])->pack_spec;
        });
    }

    //是否存在
    public function isExist(array $params)
    {
        $query = Commodity::query();
        if ($params["barcode"] ?? false) {
            $query->whereHas("barcodes", function ($query) use ($params) {
                /** @var Builder $query */
                $query->where("code", $params["barcode"]);
            });
            unset($params["barcode"]);
        }
        foreach ($params as $column => $param) {
            $query->where($column, $param);
        }
        if ($query->count() > 0) return true;
        return false;
    }

    public function getParamsByBasSku($basSku, $owner = null)
    {
        if (empty($owner)) {
            $owner = app('OwnerService')->getOwnerByCode($basSku['customerid']);
        }
        return [
            'owner_id' => $owner['id'] ?? '',
            'sku' => $basSku['sku'],
            'name' => $basSku['descr_c'],
            'length' => $basSku['skulength'],
            'width' => $basSku['skuwidth'],
            'height' => $basSku['skuhigh'],
            'volumn' => $basSku['cube'],
            "pack_spec"  => $basSku['packid'] == 'STANDARD' ? 0 : explode("/",$basSku['packid'])[1],
            "remark" => $basSku['notes'],
        ];
    }

    public function syncCommodityCreated()
    {
        $created_at = config('sync.commodity_sync.created_at');
        $create_set = config('sync.commodity_sync.cache_prefix.create_set');
        $create_keys = config('sync.commodity_sync.cache_prefix.create_keys');
        $create_key = config('sync.commodity_sync.cache_prefix.create');
        ini_set('memory_limit', '512M');

        /** @var OracleBasSkuService $oracleBasSkuService */
        $oracleBasSkuService = app(OracleBasSkuService::class);
        $last_time = $this->getCommodityLastSyncAt($created_at, 'create');
        $basSkus = $oracleBasSkuService->getWmsCreatedCommodities($last_time);
        $last_time = $basSkus->first()['addtime'];
        $last_records = $basSkus->where('addtime', $last_time);
        if (!$basSkus) return;
        $this->syncCreateCommodity($basSkus);
        $this->deleteCacheKey($create_set, $create_keys);
        $this->setLastRecordsByRedis($create_key, $create_set, $create_keys, $last_records);
        $this->setCommodityLastSyncAt($created_at, $last_time);
    }

    public function syncCommodityUpdated()
    {
        $updated_at = config('sync.commodity_sync.updated_at');
        $update_set = config('sync.commodity_sync.cache_prefix.update_set');
        $update_keys = config('sync.commodity_sync.cache_prefix.update_keys');
        $update_key = config('sync.commodity_sync.cache_prefix.update');
        ini_set('memory_limit', '1200M');
        /** @var OracleBasSkuService $oracleBasSkuService */
        $oracleBasSkuService = app(OracleBasSkuService::class);
        $last_time = $this->getCommodityLastSyncAt($updated_at, 'update');
        $basSkus = $oracleBasSkuService->getWmsUpdatedCommodities($last_time);
        $last_time = $basSkus->first()['edittime'];
        $last_records = $basSkus->where('edittime', $last_time);
        if (!$basSkus) return;
        set_time_limit(500);
        $basSkus=$basSkus->chunk(2000);
        foreach ($basSkus as $basSku){
            $this->syncUpdateCommodity($basSku);
        }
        $this->deleteCacheKey($update_set, $update_keys);
        $this->setLastRecordsByRedis($update_key, $update_set, $update_keys, $last_records);
        $this->setCommodityLastSyncAt($updated_at, $last_time);
    }

    public function syncCreateCommodity($addBasSkus)
    {
        if (count($addBasSkus) < 1) return null;
        $insert_params = $this->getParamsByBasSkus($addBasSkus);
        if (!$insert_params) return;
        $this->insertCommodities($insert_params);
        /** @var CommodityBarcodeService $commodityBarcodeService */
        $commodityBarcodeService = app(CommodityBarcodeService::class);
        if (count($insert_params) > 0) $commodityBarcodeService->createBarcodeByWms($addBasSkus);

    }

    public function insertCommodities($insert_params)
    {
        if (count($insert_params) < 1) return;
        $ownerIds = array_unique(data_get($insert_params, '*.owner_id'));
        //sort($ownerIds);
        $skus = array_unique(data_get($insert_params, '*.sku'));
        //sort($skus);
        try {
            $bool = $this->insert($insert_params,false,false,false);
            if ($bool) {
                app('LogService')->log(__METHOD__, __FUNCTION__, "批量添加 Commodity Success " . count($insert_params) . ' || ' . json_encode($insert_params));
                $commodities = Commodity::query()->whereIn('owner_id', $ownerIds)->whereIn('sku', $skus)->get();
                //$md5 = md5(json_encode([$skus, $ownerIds]));
                //if (Cache::has('commodity_' . $md5)) Cache::forget('commodity_' . $md5);
                if(count($commodities)>0) $this->pushToCache($commodities);
            } else app('LogService')->log(__METHOD__, __FUNCTION__, "批量添加 Commodity FAILED " . ' || ' . json_encode($insert_params));
        } catch (\Exception $e) {
            app('LogService')->log(__METHOD__, __FUNCTION__, "批量添加 Commodity ERROR " . ' || ' . json_encode($insert_params) . ' || ' . json_encode($e->getMessage()) . ' || ' . json_encode($e->getTraceAsString()));
        }
    }

    public function getParamsByBasSkus($addBasSkus)
    {
        $owner_sku_map = [];
        $sku = [];
        $owner_code = [];
        $owner_codes = [];
        $addBasSkus->each(function ($addBasSku) use (&$owner_sku_map, &$sku, &$owner_codes, &$owner_code) {
            if (!empty($addBasSku['customerid']) && !empty($addBasSku['sku'])) {
                $key = "owner_code_{$addBasSku['customerid']}_sku_{$addBasSku['sku']}";
                $owner_sku_map[$key] = ['owner_code' => $addBasSku['customerid'], 'sku' => $addBasSku['sku']];
                $sku[] = $addBasSku['sku'];
                $owner_code[] = $addBasSku['customerid'];
                $owner_codes[$addBasSku['customerid']] = $addBasSku['customerid'];
            }
        });
        /** @var OwnerService $ownerService */
        $ownerService = app(OwnerService::class);
        $owner_id = (function () use ($ownerService, $owner_codes) {
            $owners = $ownerService->getOwnerByCodes($owner_codes);
            $map = [];
            $owners->each(function ($owner) use (&$map) {
                $map[] = $owner['id'];
            });
            return $map;
        })();
        $owner_map = (function () use ($ownerService, $owner_codes) {
            $owners = $ownerService->getOwnerByCodes($owner_codes);
            $map = [];
            $owners->each(function ($owner) use (&$map) {
                $map[$owner['code']] = $owner['id'];
            });
            return $map;
        })();
        if (count($owner_sku_map) == 0) return null;
        $commodities = Commodity::query()
            ->whereIn('owner_id', array_unique($owner_id))
            ->whereIn('sku', array_unique($sku))
            ->get();
        $unexists = [];
        foreach ($owner_sku_map as $item) {
            $commodity = Cache::get("owner_code_{$item['owner_code']}_sku_{$item['sku']}");
            if ($commodity) continue;
            $commodity = $commodities->where('sku', $item['sku'])->where('owner_id', $owner_map[$item['owner_code']])->first();
            if ($commodity) continue;
            $items = [
                'owner_code' => $item['owner_code'],
                'sku' => $item['sku']
            ];
            $unexists[json_encode($items)] = true;
        }
        if (count($unexists) == 0) return null;
        $BasSKUs = $addBasSkus->filter(function ($bas_sku) use ($unexists) {
            $arr = [
                'owner_code' => $bas_sku['customerid'],
                'sku' => $bas_sku['sku']
            ];
            return $unexists[json_encode($arr)] ?? false;
        });

        $inner_params = (function () use ($BasSKUs, $owner_map) {
            $map = [];
            $BasSKUs->each(function ($basSku) use (&$map, $owner_map) {
                $key = $basSku['sku'].$owner_map[$basSku['customerid']];
                $map[$key] = [
                    'owner_id' => $owner_map[$basSku['customerid']] ?? '',
                    'sku' => $basSku->sku,
                    'name' => $basSku->descr_c,
                    'length' => $basSku->skulength,
                    'width' => $basSku->skuwidth,
                    'height' => $basSku->skuhigh,
                    'volumn' => $basSku->cube,
                    'created_at' => $basSku->addtime,
                    'updated_at' => $basSku->edittime,
                    'pack_spec' => $basSku->packid == 'STANDARD' ? 0 : explode("/", $basSku->packid)[1],
                    'remark' => $basSku->notes,
                ];
            });
            return $map;
        })();
        if (count($inner_params) == 0) return null;
        return $inner_params;
    }

    public function syncUpdateCommodity($addBasSkus)
    {
        $sku = [];
        $owner_codes = [];
        $addBasSkus->each(function ($addBasSku) use (&$sku, &$owner_codes) {
            if (!empty($addBasSku['customerid']) && !empty($addBasSku['sku'])) {
                $sku[] = $addBasSku['sku'];
                $owner_codes[$addBasSku['customerid']] = $addBasSku['customerid'];
            }
        });
        /**
         * @var OwnerService $ownerService
         * @var DataHandlerService $dataHandlerService
         */
        $ownerService = app(OwnerService::class);
        $dataHandlerService = app(DataHandlerService::class);
        $owner_map = (function () use ($ownerService, $owner_codes) {
            $owners = $ownerService->getOwnerByCodes($owner_codes);
            $map = [];
            $owners->each(function ($owner) use (&$map) {
                $map[$owner['code']] = $owner['id'];
            });
            return $map;
        })();
        $owner_id = (function () use ($ownerService, $owner_codes) {
            $owners = $ownerService->getOwnerByCodes($owner_codes);
            $map = [];
            $owners->each(function ($owner) use (&$map) {
                $map[] = $owner['id'];
            });
            return $map;
        })();
        $commodities = Commodity::query()
            ->whereIn('owner_id', array_unique($owner_id))
            ->whereIn('sku', array_unique($sku))
            ->get();
        $commodities_map = $dataHandlerService->dataHeader(['owner_id', 'sku'], $commodities);
        $updateParams = [[
            'id', 'name', 'sku', 'owner_id', 'length', 'width', 'height', 'volumn', 'pack_spec', 'remark', 'updated_at', 'created_at'
        ]];
        $insert_params = [];
        $updateBasSkus=collect();
        foreach ($addBasSkus as $basSku) {
            $commodity = Cache::get("owner_code_{$basSku['customerid']}_sku_{$basSku['sku']}");
            if (!$commodity) $commodity = $dataHandlerService->getKeyValue(['owner_id' => $owner_map[$basSku['customerid']], 'sku' => $basSku['sku']], $commodities_map);
                if (!$commodity) {
                    $updateBasSkus->add($basSku);
                    $key = $basSku['sku'].$owner_map[$basSku['customerid']];
                    $insert_params[$key] = [
                        'owner_id' => $owner_map[$basSku['customerid']] ?? '',
                        'sku' => $basSku->sku,
                        'name' => $basSku->descr_c,
                        'length' => $basSku->skulength,
                        'width' => $basSku->skuwidth,
                        'height' => $basSku->skuhigh,
                        'volumn' => $basSku->cube,
                        'remark' => $basSku->notes,
                        'created_at' => $basSku->addtime,
                        'updated_at' => $basSku->edittime,
                        'pack_spec' => $basSku->packid == 'STANDARD' ? 0 : explode("/", $basSku->packid)[1],
                    ];
                    continue;
                } else if (
                  $commodity->sku != $basSku->sku ||
                  $commodity->name != $basSku->descr_c ||
                  $commodity->length != $basSku->skulength ||
                  $commodity->width != $basSku->skuwidth ||
                  $commodity->height != $basSku->skuhigh ||
                  $commodity->volumn != $basSku->cube ||
                  $commodity->remark != $basSku->notes ||
                  $commodity->created_at != $basSku->addtime ||
                  $commodity->pack_spec != $basSku->pickid ||
                  $commodity->updated_at != $basSku->edittime
            ) {
                $updateBasSkus->add($basSku);
                $updateParams[] = [
                    'id' => $commodity->id,
                    'owner_id' => $owner_map[$basSku['customerid']] ?? '',
                    'sku' => $basSku->sku,
                    'name' => $basSku->descr_c,
                    'length' => $basSku->skulength,
                    'width' => $basSku->skuwidth,
                    'height' => $basSku->skuhigh,
                    'volumn' => $basSku->cube,
                    'remark' => $basSku->notes,
                    'created_at' => $basSku->addtime,
                    'updated_at' => $basSku->edittime,
                    'pack_spec' => $basSku->packid == 'STANDARD' ? 0 : explode("/", $basSku->packid)[1],
                ];
            }
        }
        if (count($insert_params) > 0) $this->insertCommodities($insert_params);
        if (count($updateParams) > 0) $this->updateCommodities($updateParams);
        /** @var CommodityBarcodeService $commodityBarcodeService */
        $commodityBarcodeService = app(CommodityBarcodeService::class);
        if (count($updateParams) > 0) $commodityBarcodeService->updateBarcodeByWms($updateBasSkus);
    }

    private function pushToCache($commodities)
    {
        $owners=Owner::query()->whereIn('id',array_unique(data_get($commodities,'*.owner_id')))->get();
        $owner_map=[];
        foreach ($owners as $owner){
            $owner_map[$owner->id]=$owner->code;
        }
        if (count($commodities) < 1) return null;
        foreach ($commodities as $commodity) {
            $commodity_key = "owner_code_{$owner_map[$commodity['owner_id']]}_sku_{$commodity['sku']}";
            Cache::put($commodity_key, $commodity);
        }
    }

    public function getCommodityLastSyncAt($key, $type)
    {
        $last_time = ValueStore::query()->where('name', $key)->value('value');
        if ($last_time) return $last_time;
        if ($type == 'create') {
            $store = Commodity::query()->orderByDesc('created_at')->first();
            if ($store) return $store->created_at;
        } else {
            $store = Commodity::query()->orderByDesc('updated_at')->first();
            if ($store) return $store->updated_at;
        }
        return Carbon::now()->subSeconds(65);
    }

    public function setCommodityLastSyncAt($key, $last_time)
    {
        $asnLastSyncAt = ValueStore::query()->updateOrCreate([
            'name' => $key,
        ], [
            'name' => $key,
            'value' => $last_time,
        ]);
        LogService::log(__METHOD__, __FUNCTION__, '修改或更新' . $key . json_encode($asnLastSyncAt));
        return $asnLastSyncAt;
    }

    public function deleteCacheKey($set, $keys)
    {
        if (Cache::get($set)) {
            $cacheKeys = Cache::get($keys);
            if (!$cacheKeys) return;
            foreach ($cacheKeys as $cacheKey) {
                Cache::forget($cacheKey);
            }
            Cache::forget($keys);
        }
    }

    public function setLastRecordsByRedis($prefixKey, $set, $keys, $last_records)
    {
        $cacheKeys = [];
        foreach ($last_records as $last_record) {
            Cache::put($prefixKey . $last_record->customerid . '_' . $last_record->sku, true);
            array_push($cacheKeys, $prefixKey . $last_record->customerid . '_' . $last_record->sku);
        }
        Cache::put($keys, $cacheKeys);
        Cache::put($set, true);
    }

    function updateCommodities($updateParams)
    {
        if (count($updateParams) < 1) return;
        $ownerIds = array_unique(data_get($updateParams, '*.owner_id'));
//        sort($ownerIds);
        $skus = array_unique(data_get($updateParams, '*.sku'));
//        sort($skus);
        $this->batchUpdate($updateParams);
//        $md5 = md5(json_encode([$skus, $ownerIds]));
//        if (Cache::has('commodity_' . $md5)) Cache::forget('commodity_' . $md5);
        $commodities = Commodity::query()->whereIn('owner_id', $ownerIds)->whereIn('sku', $skus)->get();
        if(count($commodities)>0) $this->pushToCache($commodities);
    }

    /**
     * @param array $ownerIds
     * @param array $skus
     * @param array $barcodes
     * @param bool $isSyncWms 是否开启同步wms数据  开启则必须给定 $ownerIds 和 $skus
     * @param int $paginate 分页只对  货主$ownerIds 条件
     * @param int $page
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator|mixed|null
     */
    function get_(array $ownerIds = [], array $skus = [], array $barcodes = [], $isSyncWms = false, $paginate = 100, $page = 1)
    {
        if ($paginate < 100 || fmod($paginate, 100) != 0) return null; //$paginate小于100，或取余数100不为0，异常 //取余函数fmod()
        $time = config('cache.expirations.forever');
        $status = null;
        if ($ownerIds && !$skus && !$barcodes) $status = '只有货主条件';
        if ($skus) $status = '有SKU';
        if ($barcodes && !$skus) $status = '有条码没SKU';
        if (!$status) return null;

        switch ($status) {

            case $status == '有SKU':
                if ($isSyncWms) {
                    if (!$ownerIds) return null;
                    return $this->getCommoditiesByOwnerIdsAndSKu($ownerIds,$skus);
                }
                sort($skus);
                //在取出的记录用 $ownerIds和$barcodes筛选
                $commodities = Commodity::query()
                    ->whereIn('sku', $skus)->get();
                if ($ownerIds) {
                    sort($ownerIds);
//                    $md5 = md5(json_encode([$skus, $ownerIds]));
//                    return Cache::remember('commodity_' . $md5, $time, function () use ($skus, $ownerIds, $commodities) {
                    return $commodities->whereIn('owner_id', $ownerIds);
//                    });
                }
                if ($barcodes && !$ownerIds) {
                    sort($barcodes);
                    $md5 = md5(json_encode([$skus, $barcodes]));
                    return Cache::remember('commodity_' . $md5, $time, function () use ($skus, $barcodes) {
                        return Commodity::query()
                            ->whereIn('id', function ($query) use ($barcodes) {
                                $query->from('commodity_barcodes')->select('commodity_id')->whereIn('code', $barcodes);
                            })
                            ->whereIn('sku', $skus)->get();
                    });
                }
                return $commodities;

            case $status == '有条码没SKU':
                sort($barcodes);
                $commodities = Commodity::query()
                    ->whereIn('id', function ($query) use ($barcodes) {
                        $query->from('commodity_barcodes')->select('commodity_id')->whereIn('code', $barcodes);
                    })->get();
                if ($ownerIds) {
                    sort($ownerIds);
                    $barcodes_ownerIds_md5 = md5(json_encode([$barcodes, $ownerIds]));
                    return Cache::remember('commodity_' . $barcodes_ownerIds_md5, $time, function () use ($ownerIds) {
                        return Commodity::query()->whereIn('owner_id', $ownerIds);
                    });
                }
                return $commodities;

            case $status == '只有货主条件':
                sort($ownerIds);
                $md5 = md5(json_encode([$ownerIds, $paginate, $page]));
                $key = 'commodity_' . $md5;
                $commodities = Cache::get($key);
                if (is_null($commodities))//如果缓存已失效或者无缓存则重新缓存
                {
                    $commodities = Commodity::query()
                        ->whereIn('owner_id', $ownerIds)
                        ->orderBy('owner_id', 'asc')
                        ->paginate($paginate, '*', 'page', $page);
                    Cache::add($key, $commodities->items());
                    return $commodities;
                }
                return $commodities;
        }
    }


    public function getCommoditiesByOwnerIdsAndSKu($owner_ids, $skus)
    {
        $owner_codes = Owner::query()->whereIn('id', $owner_ids)->get()->map(function ($owner) {return $owner->code;});
        $basSkus = OracleBasSKU::query()->whereIn('sku', $skus)->whereIn('customerid', $owner_codes)
            ->select('customerid', 'sku', 'descr_c', 'alternate_sku1', 'alternate_sku2', 'alternate_sku3', 'skulength', 'skuwidth', 'skuhigh', 'cube', 'packid', 'addtime', 'edittime')->get();
        $maps = [];
        foreach ($basSkus as $basSku) {
            $value = [
                'owner_code' => $basSku['customerid'],
                'sku' => $basSku['sku']
            ];
            $maps[json_encode($value)] = $value;
        }
        return $this->getCommoditiesByMaps($maps, $basSkus);
    }

    /**
     * @param $maps
     * @param null $basSkus
     * @return \Illuminate\Support\Collection|\Tightenco\Collect\Support\Collection
     * 参数maps格式 $maps[json_encode(['owner_code' => $basSku['customerid'],'sku' => $basSku['sku']])]=['owner_code' => $basSku['customerid'],'sku' => $basSku['sku']];
     */
    public function getCommoditiesByMaps($maps, $basSkus = null)
    {
        $commodities = $this->getCommodityByCacheMaps($maps);
        if (count($maps) == 0) return $commodities;
        $commoditiesInDB=$this->getCommodityByMaps($maps);
        $commodities = $commodities->concat($commoditiesInDB);
        if (count($maps) == 0) return $commodities;
        $owners = Owner::query()->whereIn('code', array_unique(data_get($maps, '*.owner_code')))->get();
        $owner_map = [];
        $owner_id_map = [];
        foreach ($owners as $owner) {
            $owner_map[$owner->id] = $owner->code;
            $owner_id_map[$owner->code] = $owner->id;
        }
        $mapOwnerCodes = [];
        $mapSkus = [];
        foreach ($maps as $map) {
            $mapSkus[] = $map['sku'];
            $mapOwnerCodes[] = $map['owner_code'];
        }
        $basSkus = OracleBasSKU::query()->whereIn('sku', $mapSkus)->whereIn('customerid', $mapOwnerCodes)
                ->select('customerid', 'sku', 'descr_c', 'alternate_sku1', 'alternate_sku2', 'alternate_sku3', 'skulength', 'skuwidth', 'skuhigh', 'cube', 'packid', 'addtime', 'edittime')->get();
        if (count($basSkus) < 1) return $commodities;
        $insert_params = [];
        $owner_ids = [];
        $skus = [];
        foreach ($basSkus as $basSku) {
            $commodity = Cache::get("owner_code_{$basSku['customerid']}_sku_{$basSku['sku']}");
            if ($commodity) continue;
            if ($basSku->sku=='NOSKU')continue;
            $owner_id = $owner_id_map[$basSku['customerid']] ?? '';
            $owner_ids[] = $owner_id;
            $skus[] = $basSku->sku;
            $insert_params[] = [
                'owner_id' => $owner_id,
                'sku' => $basSku->sku,
                'name' => $basSku->descr_c,
                'length' => $basSku->skulength,
                'width' => $basSku->skuwidth,
                'height' => $basSku->skuhigh,
                'volumn' => $basSku->cube,
                'remark' => $basSku->notes,
                'created_at' => $basSku->addtime,
                'updated_at' => $basSku->edittime,
                'pack_spec' => $basSku->packid == 'STANDARD' ? 0 : explode("/", $basSku->packid)[1],
            ];
        }
        $this->insert($insert_params);
        app('LogService')->log(__METHOD__, __FUNCTION__, "批量添加 Commodity Success " . count($insert_params) . ' || ' . json_encode($insert_params));
        $insertCommodities = Commodity::query()->whereIn('owner_id',array_unique($owner_ids))->whereIn('sku',array_unique($skus))->get();
        if(count($insertCommodities)>0) $this->pushToCache($insertCommodities);
        $commodities = $commodities->concat($insertCommodities);
        return $commodities;
    }

    public function getCommodityByCacheMaps(&$maps)
    {
        $commodities = collect();
        foreach ($maps as $key => $map) {
            $commodity = Cache::get("owner_code_{$map['owner_code']}_sku_{$map['sku']}");
            if (isset($commodity)) {
                $commodities->push($commodity);
                unset($maps[$key]);
            }
        }
        return $commodities;
    }

    public function getCommodityByMaps(&$maps, $owners = null)
    {
        $count=count($maps);
        if ($owners == null) $owners = Owner::query()->whereIn('code', array_unique(data_get($maps, '*.owner_code')))->get();
        $owner_map=[];
        foreach ($owners as $owner){
            $owner_map[$owner->id]=$owner->code;
        }
        $commodities = Commodity::query()
            ->whereIn('owner_id', data_get($owners, '*.id'))
            ->whereIn('sku', array_unique(data_get($maps, '*.sku')))
            ->get();
        foreach ($commodities as $commodity) {
            $key = json_encode(['owner_code'=>$owner_map[$commodity->owner_id],'sku'=>$commodity->sku]);
            if(isset($maps[$key]))unset($maps[$key]);
        }
        if(count($maps)!=$count) $this->pushToCache($commodities);
        return $commodities;
    }

    /**
     * 不存在则创建
     *
     * @param integer $ownerId
     * @param array $sku
     */
    public function notExistToCreate($ownerId,array $sku)
    {
       $map = [];
       foreach ($sku as $item){
           $map[$item] = true;
       }
       $commodities = Commodity::query()->where("owner_id",$ownerId)->whereIn("sku",$sku)->get();
       $commodities->each(function ($commodity)use(&$map){
            unset($map[$commodity->sku]);
       });
       $sku = array_keys($map);
       if ($sku)$this->syncWMSOrderCode($ownerId,$sku);
    }
}
