<?php

namespace App\Services;

use App\Events\BroadcastToStation;
use App\Exceptions\ErrorException;
use App\MaterialBox;
use App\Station;
use App\StationTask;
use App\StationTaskChildren;
use App\StationTaskMaterialBox;
use App\StationType;
use App\Traits\ServiceAppAop;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;

class   CacheShelfService
{
    use ServiceAppAop;

    protected $modelClass = Station::class;

    /** @var StationService $stationService */
    private $stationService;
    /** @var StationTaskMaterialBoxService $stationTaskMaterialBoxService */
    private $stationTaskMaterialBoxService;
    /** @var ForeignHaiRoboticsService $foreignHaiRoboticsService */
    private $foreignHaiRoboticsService;
    /** @var StationTaskService $stationTaskService */
    private $stationTaskService;
    /** @var StationTaskChildService $stationTaskChildService */
    private $stationTaskChildService;

    /**
     * 获取缓存架上子货架当前任务
     * @param $id
     * @return Builder[]|Collection
     */
    public function getChildStation($id)
    {
        return Station::query()->where('parent_id',$id)->with('parent','pendingStationTask.stationTaskMaterialBoxes.materialBox')->get();
    }


    /**
     * 拍灯触发任务
     * @param $locCode
     * @param $PTLAction
     * @return array|bool[]
     */
    public function lightOffTask($locCode, $PTLAction): array
    {
        $station = Station::query()->with('pendingStationTask.stationTaskMaterialBoxes.materialBox')->where('code', $locCode)->first();
        try {
            $bool = $this->putBinToStore($station);                         // 推送任务
            if($bool){
                LogService::log(__CLASS__,'lightOffTask','code' .' true'. $locCode.json_encode($station));
                return ['success' => true];
            }else{
                return ['success' => false,'errMsg' => '机器人推送失败'];
            }
        } catch (ErrorException $e) {
            LogService::log(__FUNCTION__,'缓存架推送任务失败',json_encode($e->getMessage()));
            return ['success' => false,'errMsg' => $e->getMessage()];
        }
    }

    /**
     * 推任务至海柔机器人
     * @param  $station
     * @return bool
     * @throws ErrorException
     */
    public function putBinToStore($station): bool
    {
        $this->instant($this->stationTaskMaterialBoxService, 'StationTaskMaterialBoxService');
        $this->instant($this->foreignHaiRoboticsService, 'ForeignHaiRoboticsService');
        $this->instant($this->stationService, 'StationService');
        $this->instant($this->stationTaskService, 'StationTaskService');
        $this->instant($this->stationTaskChildService, 'StationTaskChildService');

        /** @var StationTaskMaterialBox $takeStationTaskMaterialBox */
        $takeStationTaskMaterialBox = $station['pendingStationTask']['stationTaskMaterialBoxes']->first();
        $formStation = $this->stationService->getStation_byType('立库');

        // 查询是否有待处理的入库任务
        $putStationTaskMaterialBox = StationTaskMaterialBox::query()->where([
            'station_id' => $formStation['id'],
            'material_box_id' => $takeStationTaskMaterialBox['material_box_id'],
            'status' => '待处理',
        ])->first();

        // 创建入立库任务
        if(!$putStationTaskMaterialBox){
            $stationTask = $this->stationTaskService->create(1);               // 生成站任务
            $this->stationTaskService->registerStations($stationTask,[$formStation['id']]);   // 注册站任务站
            /** @var StationTaskMaterialBox $putStationTaskMaterialBox */
            $putStationTaskMaterialBox = $this->stationTaskMaterialBoxService->create([
                'station_id' => $formStation['id'],
                'material_box_id' => $takeStationTaskMaterialBox['material_box_id'],
                'status' => '待处理',
            ]);
            $putStationTaskMaterialBox['station_task_id'] = $stationTask->first()['id'];
            $putStationTaskMaterialBox['type'] = '放';
            $putStationTaskMaterialBox->update();

            $params = [[
                'station_task_id'=>$stationTask->first()['id'],
                'station_taskable_type'=>StationTaskMaterialBox::class,
                'station_taskable_id'=>$putStationTaskMaterialBox['id']
            ]];

            $this->stationTaskChildService->insert($params);    // 任务任务注册
        }

        // 推立库任务
        $isSuccess =  $this->foreignHaiRoboticsService->putBinToStore_fromCacheShelf($putStationTaskMaterialBox,$station['code']);
        if($isSuccess) $this->stationTaskMaterialBoxService->set($takeStationTaskMaterialBox,['status' => '处理中']);  // 任务推送成功 标记站任务为处理中
        else {
            $materialBoxCode = $station['pendingStationTask']['stationTaskMaterialBoxes']->first()->code ?? '';
            $this->_stationCacheBroadCast($station->code,0,'error');
            $this->_stationCacheLightOn($station->code,$materialBoxCode,'拍灯重试任务');
        }
        return $isSuccess;
    }

    /**
     * 创建站任务和料箱任务
     * @param $stationCode
     * @param $materialBoxCode
     * @return array
     */
    public function createStationTask($stationCode,$materialBoxCode): array
    {
        $this->instant($this->stationTaskService, 'StationTaskService');
        $this->instant($this->stationTaskMaterialBoxService,'StationTaskMaterialBoxService');
        $this->instant($this->stationTaskChildService,'StationTaskChildService');

        $station = Station::query()->where('code' , $stationCode)->first();
        if(!$station){
            $arr = [];
            preg_match('/^HAI([\w]+)/',$stationCode,$arr);
            $parentCode = $arr[1] ?? '';
            $stationType = StationType::query()->where('name','缓存架')->first();
            $parentStation = Station::query()->firstOrCreate(['code'=>$parentCode],['station_type_id'=>$stationType['id']]);
            $station = Station::query()->firstOrCreate(['code' => $stationCode,'parent_id'=>$parentStation['id']],['name'=>$stationCode,'station_type_id' => $stationType['id']]);
        }

        $materialBox = MaterialBox::query()->firstOrCreate(['code' => $materialBoxCode]);

        $station->load('pendingStationTask.stationTaskMaterialBoxes.materialBox');
        if($station->pendingStationTask){
            if($station['pendingStationTask']['stationTaskMaterialBoxes']->first()->materialBox->code == $materialBoxCode){
                $response = $this->_stationCacheLightOn($stationCode,$materialBoxCode,'任务重试');
                if($response->code) return ['success'=>true,'message' =>  '任务重试'];
                return ['success'=>true,'message' =>  '任务重试失败'];
            }
            return ['success' => false,'message' => '当前已有进行重的任务'];
        }

        $stationTask = $this->stationTaskService->create(1);                                                       // 生成站任务
        $stationTaskMaterialBox = $this->stationTaskMaterialBoxService->createByStationAndMaterialBox($station,$materialBox);     // 创建料箱任务
        $this->stationTaskService->registerStations($stationTask,[$station['id']]);                                               // 注册站任务站
        $stationTaskMaterialBox['station_task_id'] = $stationTask->first()['id'];
        $stationTaskMaterialBox->update();
        $params = [[
                'station_task_id'=>$stationTask->first()['id'],
                'station_taskable_type'=>StationTaskMaterialBox::class,
                'station_taskable_id'=>$stationTaskMaterialBox['id']
            ]];
        $this->stationTaskChildService->insert($params);                                                                        // 任务任务注册

        $body = $this->_stationCacheLightOn($stationCode,$materialBoxCode);
        if($body->code == 200)return ['success'=>true];
        return ['success' => false,'message' => '机器人亮灯异常'];
    }

    /**
     * 控制格口亮灯
     * @param $locCode
     * @param null $materialCode
     * @param string $title
     * @param string $color
     * @return mixed
     */
    public function _stationCacheLightOn($locCode,$materialCode = null,$title = 'title' ,string $color = '1')
    {
        $params = [
            "areaCode" => "1004",
            'locCode' => $locCode,
            'PTLAction' => 1,
            'PTLSettings' => ['color'=> $color, 'frequency'  =>1],
            "displayInfo" => [
                "detail01" => $materialCode,
                "detail02" => "detail02",
                "detail03" => "detail03",
                "qrCode" => "qrCode",
                "qty00" => "11",
                "qty01" => 1,
                "qty02" => 2,
                "title" => $title,
                "uomDesc01" => "uo",
                "uomDesc02" => "uo"
            ],
        ];
        return new MaterialBox(['code' => 200]);
//        $response = Http::post(config('api.haiq.storage.light'), $params);
//        return json_decode($response->body());
    }

    /**
     * 控制格口灭灯
     * @param $locCode
     * @return mixed
     */
    public function _stationCacheLightOff($locCode){
        if(!$locCode)return null;
        $params = [
            "areaCode" => "1004",
            'locCode' => $locCode,
            'PTLAction' => 0,
        ];
        $response = Http::post(config('api.haiq.storage.light'), $params);
        return json_decode($response->body());
    }

    /**
     * 广播 type success成功 error 异常
     * @param $locCode
     * @param $PTLAction
     * @param string $type
     */
    public function _stationCacheBroadCast($locCode, $PTLAction,string $type = 'success')
    {
        if($PTLAction == 0){
            $station = Station::query()->with('parent')->where('code',$locCode)->first();

            $json = json_encode( [
                'station_id' => $station['parent']['id'],
                'code'  => $station['parent']['code'],
                'gird_id' => $station['id'],
                'grid_code' => $station['code'],
                'type' => $type
            ]);
            broadcast(new BroadcastToStation($station['parent_id'],$json));
        }
    }

    /**
     * 根据立库任务完成 缓存架任务 和 入立架任务
     * @param StationTaskMaterialBox $putStationTaskMaterial
     */
    public function putStationTaskMaterialBoxProcess(StationTaskMaterialBox $putStationTaskMaterial)
    {
        $this->instant($this->stationTaskMaterialBoxService,'StationTaskMaterialBoxService');

        $takeStationTaskMaterialBox = StationTaskMaterialBox::query()->with('station','stationTask')->where('material_box_id',$putStationTaskMaterial['material_box_id'])->whereIn('station_id',function($query){
            $query->from('stations')->selectRaw('id')->whereIn('station_type_id',function($query){
                $query->from('station_types')->selectRaw('id')->where('name','缓存架');
            });
        })->where('status','处理中')->first();

        if(!$takeStationTaskMaterialBox)return ;
        $this->stationTaskMaterialBoxService->set($takeStationTaskMaterialBox, [
            'status' => '完成'
        ]);

        // 缓存架任务
        if($takeStationTaskMaterialBox->stationTask)$takeStationTaskMaterialBox->stationTask->update(['status' => '完成']);
        // 入立架任务
        if($putStationTaskMaterial->stationTask)$putStationTaskMaterial->stationTask->update(['status' => '完成']);

        $this->_stationCacheLightOff($takeStationTaskMaterialBox->station->code ?? null);  //海柔格口灭灯
        $this->_stationCacheBroadCast($takeStationTaskMaterialBox->station->code, 0);    //通知缓存架任务完成
    }

    /**
     * 取消任务
     * @param $stationCode
     * @return array
     */
    public function clearTask($stationCode): array
    {
        $station = Station::query()->with(['currentStationTask.stationTaskMaterialBoxes.materialBox',
            'pendingStationTask.stationTaskMaterialBoxes.materialBox'])
            ->where('code',$stationCode)->first();

        if($station->currentStationTask)return ['success' => false,'message' => '当前任务正在执行','data'=>$stationCode];
        if($station->pendingStationTask->stationTaskMaterialBoxes->count() == 0){
            $station->pendingStationTask->delete();
            return ['success' => true];
        }

        $taskStationTaskMaterialBox = $station->pendingStationTask->stationTaskMaterialBoxes->first() ?? null;
        $stationTaskMaterialBoxes = StationTaskMaterialBox::query()->with('stationTask')
            ->where('material_box_id',$taskStationTaskMaterialBox['material_box_id'])
            ->where('station_id','!=',$station->pendingStationTask['id'])
            ->get();

        foreach ($stationTaskMaterialBoxes as $stationTaskMaterialBox) {
            if($stationTaskMaterialBox->stationTask){
                StationTaskChildren::query()->where([
                    'station_task_id' => $stationTaskMaterialBox->stationTask['id'],
                    'station_taskable_type'=>StationTaskMaterialBox::class,
                    'station_taskable_id'=>$stationTaskMaterialBox['id']])->delete();

                $stationTaskMaterialBox->stationTask->delete();
            }
            $stationTaskMaterialBox->delete();
        }
        return ['success' => true];
    }
}
