<?php

namespace App\Services;

use App\Events\AddOrUpdateOrderIssues;
use App\OracleActAllocationDetails;
use App\OracleDOCASNHeader;
use App\OracleDOCOrderHeader;
use App\OrderIssue;
use App\OrderIssueProcessLog;
use App\OrderIssueType;
use App\OrderPackage;
use App\Order;
use App\RejectedBill;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Ramsey\Uuid\Uuid;
use App\Traits\ServiceAppAop;


class OrderIssueService
{
    use ServiceAppAop;
    protected $modelClass=OrderIssue::class;

    public function insert($params)
    {
        OrderIssue::query()->insert($params);
    }

    public function orderIssueTag(array $params)
    {
        $orderNos = $params['orderNos'];
        /** @var OracleDOCOrderHeaderService $orderHeaderService */
        $orderHeaderService = app('OracleDocOrderHeaderService');
        $orderHeaders = $orderHeaderService->getQuery()->whereIn('orderNo', $orderNos)->get();
        $bool = $this->createOrderIssueByWmsOrder($orderHeaders, $params['typeId'], $params['result_explain']);
        if ($bool) {
            return ['success' => $bool];
        } else {
            return ['success' => $bool, 'fail_info' => '问题件创建失败,请检查勾选订单的状态'];
        }
    }

    public function createOrderIssueByWmsOrder($orderHeaders, $order_issue_type_id, $result_explain, $imported_status = '正常', $custom_code = null,$hiddenTag = null)
    {
        /** @var OrderService $orderService */
        $orderService = app('OrderService');
        $orderService->syncOrderInfo($orderHeaders);
        $orders = Order::query()->whereIn('code',data_get($orderHeaders,'*.orderno'))->whereHas('packages')->get();
        if($orders->count()==0)return false;
        $innerParams = [];
        $data = Carbon::now()->format('Y-m-d H:i:s');
        foreach ($orderHeaders as $orderHeader) {
            $order = $orders->where('code',$orderHeader->orderno)->first();
            if($order==null)$order = Order::query()->where('code',$orderHeader->orderno)->first();
            $innerParams[] = [
                'order_id' => $order->id,
                'order_issue_type_id' => $order_issue_type_id,
                'result_explain' => $result_explain,
                'imported_status' => $imported_status,
                'custom_code' => $custom_code,
                'hidden_tag' => $hiddenTag,
                'updated_at' => $data,
                'created_at' => $data
            ];
        }
        try {
            $this->insert($innerParams);
            $ordersIssues = OrderIssue::query()->whereIn('order_id', data_get($innerParams, '*.order_id'))->get();
            event(new AddOrUpdateOrderIssues(data_get($ordersIssues,'*.order_id')));
            $this->同步退单状态($ordersIssues);
            $param = [
                'ids' => data_get($ordersIssues, '*.id'),
                'content' => '',
                'user_id' => Auth::user()['id'],
                'type' => '创建'
            ];
            app(OrderIssueProcessLogService::class)->create($param);
            app('LogService')->log(__METHOD__, __FUNCTION__, '创建问题件' . count($innerParams) . json_encode($innerParams));
            return true;
        } catch (\Exception $e) {
            app('LogService')->log(__METHOD__, __FUNCTION__, '创建问题件 error' . count($innerParams) . json_encode($innerParams) .json_encode($e->getMessage())  .json_encode($e->getTraceAsString())) ;
            return false;
        }
    }

    public function 同步退单状态($orderIssues)
    {
        if(!$orderIssues)return;
        foreach ($orderIssues as $orderIssue) {
            /**@var OrderIssue $orderIssue */
            $orderIssue->syncRejectedBills();
            $orderIssue->syncRejectingStatus();
        }
    }

    public function createOrFindByOrderNo($orderNo)
    {
        $orderHeader = OracleDOCOrderHeader::query()->where('orderNo', $orderNo)->first();
        if (!$orderHeader) {
            return null;
        }
        return $this->createOrFind($orderHeader['soreference1']);
    }

    public function createOrFind($clientCode)
    {
        /** @var OrderService $orderService */
        $orderService = app('OrderService');
        $orderHeader = OracleDOCOrderHeader::query()->where('SOReference1', $clientCode)->first();
        if ($orderHeader === null) {
            return null;
        }
        $order = $orderService->findOrCreateByClientCode($clientCode);
        $rejectedBill = RejectedBill::query()->where('order_number', $orderHeader['soreference1'])->first();
        if ($rejectedBill === null) {
            $asnHeader = OracleDOCASNHeader::query()->where('ASNReference2', $orderHeader['soreference1'])->first();
            if ($asnHeader['asnreference3'] ?? false) {
                $rejectedBill = RejectedBill::query()->where('logistic_number_return', $asnHeader['asnreference3'])->first();
            }
        }
        $arr = [
            'order_id' => $order['id'],
            'logistic_number_return' => $rejectedBill['logistic_number_return'] ?? '',
        ];
        $orderIssue = null;
        try {
            /** @var OrderIssue $orderIssue */
            $orderIssue = OrderIssue::query()->create($arr);
            $orderIssue->syncRejectedBills();
            $orderIssue->syncRejectingStatus();
            $orderIssue->order = $order;
            event(new AddOrUpdateOrderIssues([$orderIssue['order_id']]));
            app('LogService')->log(__METHOD__, __FUNCTION__, '创建问题件' . json_encode($orderIssue));
        } catch (\Exception $e) {
            app('LogService')->log(__METHOD__, __FUNCTION__, '创建问题件error' . json_encode($arr) . $e->getMessage() . $e->getTraceAsString());
        } finally {
            unset($orderHeader, $rejectedBill, $order);
            return $orderIssue;
        }
    }

    public function validatorCreate(Request $request)
    {
        return Validator::make($request->input(), [
            'rejected_bill_id' => ['nullable'],
            'order_id' => ['nullable'],
            'owner_id' => ['required'],
            'second_order_id' => ['nullable'],
            'logistic_id' => ['nullable'],
            'order_issue_type_id' => ['required'],
            'baoshi_indemnity_money' => ['numeric', 'nullable'],
            'logistic_indemnity_money' => ['numeric', 'nullable'],
            'final_status' => ['nullable'],
            'result_explain' => ['nullable']
        ], [
            'required' => ':attribute 为必填项',
            'unique' => ':attribute 已存在',
            'numeric' => ':attribute 为数组',
        ], [
            'owner_id' => '货主',
            'rejected_bill_id' => '退回单号',
            'order_id' => '订单ID',
            'second_order_id' => '退回订单id',
            'logistic_id' => '承运人',
            'order_issue_type_id' => '问题类别',
            'baoshi_indemnity_money' => '宝时赔偿金额',
            'logistic_indemnity_money' => '承运商赔偿金额',
            'final_status' => '最终状态',
            'result_explain' => '处理结果说明',
        ]);
    }

    public function create(array $arr)
    {
        /** @var OrderIssue $orderIssue */
        $orderIssue = OrderIssue::query()->create($arr);
        if (!$arr['order_id']) {
            $order = app("OrderService")->createOrder($arr);
            $orderIssue->order_id = $order['id'];
            $orderIssue->save();
            app('LogService')->log(__METHOD__,__FUNCTION__,'创建 Order'.json_encode($order));
        }
        $orderIssue->syncRejectedBills();
        $orderIssue->syncRejectingStatus();
        return $orderIssue;
    }

    public function createByLogisticNumber(array $arr)
    {
        /** @var OrderIssue $orderIssue */
        $arr['code']='null_'.Uuid::uuid4();
        $order = app("OrderService")->createOrder($arr);
        app('LogService')->log(__METHOD__,__FUNCTION__,'创建 Order'.json_encode($order));
        $orderIssue = OrderIssue::query()->create($arr);
        $orderIssue['order_id'] = $order['id'];
        OrderPackage::query()->create(['order_id' => $order['id'], 'logistic_number' => $arr['logistic_number_return']]);
        $orderIssue->update(['order_id' => $order['id']]);
        $orderIssue->syncRejectedBills();
        $orderIssue->syncRejectingStatus();
        event(new AddOrUpdateOrderIssues([$orderIssue['order_id']]));
        return $orderIssue;
    }

    public function batchDestroy($ids): array
    {
        try {
            $bool = OrderIssue::query()->whereIn('id', $ids)->delete();
            app('LogService')->log(__METHOD__, __FUNCTION__, json_encode($ids));
            return ['success' => $bool];
        } catch (\Exception $e) {
            app('LogService')->log(__METHOD__, __FUNCTION__, 'error' . json_decode($ids) . '||' . $e->getMessage() . '||' . $e->getTraceAsString());
            return ['success' => false];
        }
    }

    public function endOrderIssues(array $ids): int
    {
        return OrderIssue::query()->whereIn('id', $ids)->update(['final_status' => '已解决']);
    }

    public function isExistOrderIssueTypeIsEnd($ids): bool
    {
        return OrderIssueProcessLog::query()->whereIn('order_issue_id',$ids)->where('type','结束')->exists();
    }

    public function editOrderIssueSecondClientNo($id, $secondClientNo, &$order = null): bool
    {
        $orderService = app(OrderService::class);
        $orderHeaderService = app('OracleDocOrderHeaderService');
        $orderHeaders = $orderHeaderService->getQuery()->where('SoReference1', $secondClientNo)->get();
        $orderService->syncOrderInfo($orderHeaders,false);
        return OrderIssue::query()->where('id', $id)->update(['second_client_no' => $secondClientNo]) > 0;
    }

    public function updateSecondLogisticNumber($id, $logisticNumber): array
    {
        $orderIssue = OrderIssue::query()->where('id',$id)->first();
        // 有填写二次订单号 并没有对应的订单号
        if($orderIssue->second_client_no){
            if(!$orderIssue->secondOrder){
                $orderIssue->update(['second_logistic_number'=>$logisticNumber]);
                return ['success' => true,'second_logistic_number' => $logisticNumber];
            }else{
                return ['success' => false,'message' => '二次客户订单号对应的订单已存在,无法更改快递单号'];
            }
        }
//        // 没有填写二次订单号
//        $order = app(OrderService::class)->getOrderByLogisticNumber($logisticNumber);
//        if (is_null($order)) {
//            $orderIssue->update(['second_logistic_number' => $logisticNumber]);
//            return ['success' => true, 'second_logistic_number' => $logisticNumber];
//        }
//        $orderIssue->update(['second_client_no' => $order->client_code]);

        $orderIssue->second_logistic_number = $logisticNumber;
        $order_package = OrderPackage::query()->selectRaw('order_id')->where('logistic_number',$logisticNumber);
        if($order_package){
            $order = Order::query()->with(['packages.commodities.commodity', 'logistic'])
                ->whereIn('id', $order_package)->first();
            if($order)$orderIssue->second_client_no = $order->client_code;
            $orderIssue->save();
            return ['success' => true, 'order' => $order];
        }
        /**
         * @var OracleDOCOrderHeaderService $orderHeaderService
         * @var OrderService $orderService
         */
        $orderHeaderService = app(OracleDOCOrderHeaderService::class);
        $orderService = app(OrderService::class);
        $orderHeader = $orderHeaderService->getQuery()->where("DOC_Order_Header.SOReference5",$logisticNumber)->get();
        if(count($orderHeader) == 0){
            $actAllocationQuery = OracleActAllocationDetails::query()->selectRaw("OrderNo")->where("PickToTraceId",$logisticNumber);
            $orderHeader = $orderHeaderService->getQuery()->whereIn("DOC_Order_Header.OrderNo",$actAllocationQuery)->get();
        }
        if(count($orderHeader)>0){
            $orderService->syncOrder($orderHeader);
            $order = Order::query()->with(['packages.commodities.commodity', 'logistic'])->where("code",$orderHeader->first()->orderno)->first();
            if($order){
                $orderIssue->update(['second_client_no'=>$order->client_code]);
                return ['success' => true, 'order' => $order];
            }
        }
        $orderIssue->update(['second_logistic_number'=>$logisticNumber]);
        return ['success' => true, 'order' => null];

    }

    public function createOrderIssue($logisticNumber, $type, $result_explain, $importedStatus = '正常', $custom_code = null,$hiddenTag = null): bool
    {
        $orderHeaders = OracleDOCOrderHeader::query()->with(['oracleDOCOrderDetails', 'actAllocationDetails', 'oracleBASCode','orderType'])
            ->whereHas('actAllocationDetails', function ($query) use ($logisticNumber) {
                $query->where('picktotraceid', $logisticNumber);
            })->get();
        $orderIssueType = OrderIssueType::query()->where('name', $type)->first();
        return $this->createOrderIssueByWmsOrder($orderHeaders, $orderIssueType->id, $result_explain, $importedStatus, $custom_code,$hiddenTag);
    }

    /**
     * @param array $logisticNumbers
     * @return array
     */
    public function 校验问题件是否存在_快递单号_返回存在的快递单号($logisticNumbers): array
    {
        $orderIssues = OrderIssue::query()->with('order.packages')->whereHas('order.packages', function ($query) use ($logisticNumbers) {
            $query->whereIn('logistic_number', $logisticNumbers);
        })->get();
        $exits_logistic_number = array_diff(array_unique(data_get($orderIssues, '*.order.packages.*.logistic_number')), ['', null]);
        return array_intersect($exits_logistic_number, $logisticNumbers);
    }

    /**
     * @param array $orderNos
     * @return array
     */
    public function 校验问题件是否存在_WMS订单号_返回存在的订单号($orderNos): array
    {
        $orderIssues = OrderIssue::query()->with('order')->whereHas('order', function ($query) use ($orderNos) {
            $query->whereIn('code', $orderNos);
        })->get();
        $exits_logistic_number = array_diff(array_unique(data_get($orderIssues, '*.order.code')), ['', null]);
        return array_intersect($exits_logistic_number, $orderNos);
    }

    public function checkOrderIssueIsExistAndSoftDelete($orderNos): array
    {
        $orderIssues = OrderIssue::query()->onlyTrashed()->whereIn('order_id',function($query)use($orderNos){
            $query->from('orders')->selectRaw('id')->whereIn('code',$orderNos);
        })->get();
        $exits_logistic_number = array_diff(array_unique(data_get($orderIssues, '*.order.code')), ['', null]);
        return array_intersect($exits_logistic_number, $orderNos);
    }

    /**
     * 导入处理字段
     * @param array $ids
     * @return array|bool[]
     */
    public function disposeImport(array $ids): array
    {
        $orderIssues = OrderIssue::query()->with('order')->whereIn('id', $ids)->get();
        if ($orderIssues->count()<count($ids)) {
            $is_exits_ids = array_diff($ids, data_get($orderIssues, '*.code'));
            return ['success' => false, 'fail_info' => json_encode($is_exits_ids) . '没有存在对应的问题件'];
        }
        if ($orderIssues->where('imported_status', '导入已梳理')->count() > 0) {
             $is_dispose_orderNos = data_get($orderIssues->where('imported_status', '导入已梳理'), '*.order.code');
            return ['success' => false, 'fail_info' => json_encode($is_dispose_orderNos) . '导入已处理'];
        }
        try {
            OrderIssue::query()->whereIn('id', $ids)->update(['imported_status' => '导入已梳理']);
            app('LogService')->log(__METHOD__,__FUNCTION__,'导入处理 '.json_encode($ids).'导入处理');
            return ['success' => true];
        } catch (\Exception $e) {
            app('LogService')->log(__METHOD__,__FUNCTION__,'导入处理 error'.json_encode($e->getMessage()).$e->getTraceAsString());
            return ['success' => false,'fail_info'=>$e->getMessage()];
        }
    }

    public function getRecycleBinPaginate($params){
        return OrderIssue::query()
            ->with(['order'=>function($query){
                $query->with(['logistic','shop','owner','packages'=>function($query){
                $query->with('commodities');
            }]);
        },'orderIssueRejectedBills.rejectedBill.items','issueType','secondOrder.packages.commodities'])->onlyTrashed()->paginate($params['paginate'] ?? 50);
    }

    public function recoverOrderIssue($ids): array
    {
        try {
            $bool = OrderIssue::query()->withTrashed()->whereIn('id', $ids)->restore();
            app('LogService')->log(__METHOD__, __FUNCTION__, '恢复问题件 ids = ' . json_encode($ids));
            return ['success'=>$bool];
        } catch (\Exception $e) {
            app('LogService')->log(__METHOD__, 'ERROR '.__FUNCTION__, '恢复问题件 Error' . json_encode($ids).' || '.json_encode($e->getMessage()).' || '.json_encode($e->getTraceAsString()));
            return ['success'=>false,'error'=>$e->getMessage()];
        }
    }

    /**
     * 归档
     * @param $orderIssues
     */
    public function archive($orderIssues)
    {
        $updateParams = ['final_status'=>'已归档','archive_at' =>  Carbon::now()->format('Y-m-d H:i:s')];
        $orderIssues->each(function($orderIssue)use($updateParams){
            $orderIssue->update($updateParams);
        });
    }
}
