<?php

namespace App\Jobs;

use App\library\zop\ZopClient;
use App\library\zop\ZopProperties;
use App\library\zop\ZopRequest;
use App\OrderPackage;
use App\Services\LogService;
use App\Services\OrderPackageReceivedSyncService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Carbon;

class LogisticZopSync implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $logistic_number;

    /**
     * Create a new job instance.
     *
     * @param $logistic_number
     */
    public function __construct($logistic_number)
    {
        $this->logistic_number = $logistic_number;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        ini_set('max_execution_time', 60);
        LogService::log(LogisticZopSync::class, "{$this->logistic_number}-JOB-ZOP", '');
        $zopResult = [];
        $response = $this->sentRequestToZT();
        if(is_null($response)) return;
        if ($response->status) {
            $zopResult[] = [
                'routes' => $response->result,
                'logisticNum' => $this->logistic_number,
            ];
        }
        $result = $this->transformRoutes($zopResult);
        /* @var $orderPackageReceivedSyncService OrderPackageReceivedSyncService */
        $orderPackageReceivedSyncService = app('OrderPackageReceivedSyncService');
        !empty($result) && $orderPackageReceivedSyncService->update($result);
    }

    /**
     * 转换快递路由信息
     * @param array $routs 快递路由
     * @return array
     */
    public function transformRoutes(array $routs): array
    {
        $result = [];
        foreach ($routs as $route) {
            $result = $this->transformRouteItem($route, $result);
        }
        return $result;
    }

    /**
     * @param $route
     * @param array $result
     * @return array
     */
    private function transformRouteItem($route, array $result): array
    {
        $resultItem = [];
        $resultItem['logistic_number'] = $route['logisticNum'];
        $itemRoutes = $route['routes'];
        $lastRoute = null;
        if (!empty($itemRoutes)) {
            $lastRoute = $itemRoutes[count($itemRoutes) - 1];
            $resultItem = $this->getNormalStatusAndReceivedAt($lastRoute, $resultItem);
            $resultItem['transfer_status'] = $this->getTransferStatus($itemRoutes);
        } else {
            $resultItem['status'] = null;
            $resultItem['transfer_status'] = [];
        }
        if (!array_key_exists('status', $resultItem)) {
            $resultItem['status'] = null;
            $resultItem['transfer_status'] = [];
        }
        try {
            $orderPackageReceivedSyncService = app('OrderPackageReceivedSyncService');
            $exceptionData = $orderPackageReceivedSyncService->setExceptionType($resultItem, $lastRoute ? $lastRoute->scanDate / 1000 : null);
            $resultItem['exception_type'] = $exceptionData['exception_type'];
            $resultItem['exception'] = $exceptionData['exception'];
        } catch (\Exception $e) {
        }
        if ($resultItem['status'] == null) {
            unset($resultItem['status']);
            unset($resultItem['transfer_status']);
        }
        //如果没有发现额外的异常，且查询到物流轨迹，将异常置为无
        if (!array_key_exists('exception', $resultItem)
            && !array_key_exists('exception_type', $resultItem)
            && array_key_exists('transfer_status', $resultItem)
        ) {
            $resultItem['exception_type'] = '无';
            $resultItem['exception'] = '否';
        }
        $resultItem['routes_length'] = array_key_exists('transfer_status', $resultItem) ? count($resultItem['transfer_status']) : 0;
        $result[] = $resultItem;
        return $result;
    }
    /**
     * 正常的状态与签收时间
     * @param $lastRoute
     * @param array $resultItem
     * @return array
     */
    private function getNormalStatusAndReceivedAt($lastRoute, array $resultItem): array
    {
        switch ($lastRoute->scanType) {
            case '收件':
                $resultItem['status'] = '已揽收';
                break;
            case '到件':
            case '发件':
                $resultItem['status'] = '在途';
                break;
            case 'ARRIVAL':
            case '派件':
                $resultItem['status'] = '派送中';
                break;
            case 'SIGNED':
            case '签收':
                $resultItem['status'] = '已收件';
                $resultItem['received_at'] = Carbon::parse($lastRoute->scanDate / 1000)->toDateTimeString();
                break;
            default:
                $resultItem['status'] = '无';
                break;
        }
        return $resultItem;
    }

    /**
     * @param $itemRoutes
     * @return array
     */
    private function getTransferStatus($itemRoutes): array
    {
        $transfer_status = [];
        foreach ($itemRoutes as $item) {
            $data = [];
            $data['accept_time'] = Carbon::parse($item->scanDate / 1000)->toDateTimeString();
            $scanSite = $item->scanSite;
            $data['accept_address'] = $scanSite->prov . '-' . $scanSite->name;
            $data['remark'] = $item->scanType;

            $transfer_status[] = $data;
        }
        return $transfer_status;
    }

    /**
     * 发送请求到中通
     * @return mixed
     */
    private function sentRequestToZT()
    {
        $url = config('api_logistic.ZTO.url');
        $xAppKey = config('api_logistic.ZTO.x-appKey');
        $appSecret = config('api_logistic.ZTO.appSecret');
        $properties = new ZopProperties($xAppKey, $appSecret);
        $client = new ZopClient($properties);
        $request = new ZopRequest();

        $request->setUrl($url);
        $request->setBody(json_encode([
            'billCode' => $this->logistic_number,
        ],JSON_UNESCAPED_UNICODE));
        return json_decode($client->execute($request));
    }
}
