<?php
namespace app\common\model;
use app\hander\HelpHander;
use think\Exception;
use think\Db;
class DeviceTask extends Base {

    public function updates(){
        $post = request()->post();

        $result = validate('DeviceTask')->check($post,[]);
        if(true !== $result){
            $this->error = validate('DeviceTask')->getError();
            return false;
        }
        if(!$post['addrs']){
            $this->error='任务地点不能为空';
            return false;
        }
        if(!$post['user_ids']){
            $this->error='检查人员不能为空';
            return false;
        }
//        if(strtotime($post['start_time']) < time()){
//            $this->error = '开始时间不能小于当前时间';
//            return false;
//        }
        if($post['start_time'] >= $post['end_time']){
            $this->error = '结束时间请大于开始时间';
            return false;
        }
        //添加操作
        if($post['id']  == 0){
            $post['addrs']=explode(',',$post['addrs']);
            $post['user_ids']=explode(',',$post['user_ids']);
            $curtime = date('Y-m-d H:i:s');

            $data = array(
                'org_id' => cur_org_id(),
                'title' => $post['title'],
                'status' => 0,
                'create_time' => $curtime,
                'cate_id' => $post['cate_id'],
                'uuid' => new_guid(),        //TODO::是否检测已重复
            );
            if(date('Y-m-d',strtotime($post['start_time'])) != date('Y-m-d',strtotime($post['end_time']))){ //跨天,执行连续天数为0
                $post['days'] = 0;
            }
            $timearr = $this->get_time_arr($post['start_time'],$post['end_time'],$post['hours'],$post['days']);

            Db::startTrans();
            try{
                foreach ($timearr as $k=>$v){
                    $data['start_time'] = $v['start_time'];
                    $data['end_time'] = $v['end_time'];
                    $data['create_yyyymm'] = date('Ym',strtotime($data['start_time']));
                    $data['create_yyyy'] = date('Y',strtotime($data['start_time']));
                    $data['create_yyyymmdd'] = date('Ymd',strtotime($data['start_time']));
                    //添加任务
                    $taskid = Db::name('device_task')->insertGetId($data);
                    if(!$taskid){
                        exception('创建任务失败');
                    }

                    //添加检查地点
                    $addr = array();
                    $post['addrs'] = array_unique($post['addrs']);
                    foreach ($post['addrs'] as $k=>$v){
                        $addr[] = array(
                            'task_id' => $taskid,
                            'device_id' => $v
                        );
                    }
                    $taskAddr=Db::name('device_task_addr')->insertAll($addr);
                    if(!$taskAddr){
                        exception('任务地点保存失败');
                    }

                    //添加检查人员
                    $user = array();
                    $post['user_ids'] = array_unique($post['user_ids']);
                    foreach ($post['user_ids'] as $k=>$v){
                        $user[] = array(
                            'task_id' => $taskid,
                            'user_id' => $v
                        );
                    }
                    $taskUser=Db::name('device_task_user')->insertAll($user);
                    if(!$taskUser){
                        exception('任务地点保存失败');
                    }
                }

                Db::commit();
                return true;
            }catch (\Exception $e){
                // 回滚事务
                $this->error = $e->getMessage();
                Db::rollback();
                return false;
            }
        }
        //编辑操作
        if($post['id'] > 0){
            $curtime = date('Y-m-d H:i:s');
            $data = array(
                'title' => $post['title'],
                'cate_id' => $post['cate_id'],
                'update_time' => $curtime,
                'start_time' => $post['start_time'],
                'end_time' => $post['end_time'],
                'create_yyyymm' => date('Ym',strtotime($post['start_time'])),
                'create_yyyy' => date('Y',strtotime($post['end_time'])),
                'create_yyyymmdd' => date('Ymd',strtotime($post['start_time'])),
            );

            $taskInfo=$this->getTaskOne($post['id']);
            $addrIds=explode(',',$post['addrs']);
            $userIds=explode(',',$post['user_ids']);

            $addrnew = array_diff($addrIds,$taskInfo['old_addrs']);
            $addrdef = array_diff($taskInfo['old_addrs'],$addrIds);

            $usernew = array_diff($userIds,$taskInfo['old_user_ids']);

            $userdef = array_diff($taskInfo['old_user_ids'],$userIds);
            Db::startTrans();
            try {
                //编辑任务
                $res = Db::name('device_task')->where('id',$post['id'])->update($data);
                if(!$res){
                    exception('编辑任务失败');
                }
                //编辑检查地点
                if($addrdef){
                    $delAddr=Db::name('device_task_addr')->where('task_id',$post['id'])->whereIn('device_id',$addrdef)->delete();
                    if(!$delAddr){
                        exception('地点编辑失败');
                    }
                }

                if($addrnew){
                    $baddr = array();
                    foreach ($addrnew as $k=>$v){
                        $baddr[] = array(
                            'task_id' => $post['id'],
                            'device_id' => $v
                        );
                    }
                    $addTaskAddr=Db::name('device_task_addr')->insertAll($baddr);
                    if(!$addTaskAddr){
                        exception('地点编辑失败');
                    }
                }
                //添加检查人员
                if($userdef){
                    $delTaskUser=Db::name('device_task_user')->where('task_id',$post['id'])->whereIn('user_id',$userdef)->delete();
                    if(!$delTaskUser){
                        \exception('检查人员编辑失败');
                    }
                }
                if($usernew){
                    $buser = array();
                    foreach ($usernew as $k=>$v){
                        $buser[] = array(
                            'task_id' => $post['id'],
                            'user_id' => $v
                        );
                    }
                    $addTaskUser=Db::name('device_task_user')->insertAll($buser);
                    if(!$addTaskUser){
                        \exception('检查人员编辑失败');
                    }
                }
                Db::commit();
                return true;
            }catch (\Exception $e){
                $this->error = $e->getMessage();
                Db::rollback();
                return false;
            }

        }

    }

    /**
     * 格式化时间,获取时间数组
     * @param $starttime 开始时间
     * @param $endtime 结束时间
     * @param $hours 重复小时
     * @param $days 执行天数
     * @return array
     */
    private function get_time_arr($starttime,$endtime,$hours,$days){
        $onehour = 60*60;
        $oneday = 24*60*60;
        $start = strtotime($starttime);
        $end = strtotime($endtime);
        $ctime = $end - $start;
        $timearr = array();

        $timearr[] = array(
            'start_time' => $starttime,
            'end_time' => $endtime,
        );
        if($hours > 0){
            if($ctime > $hours*$onehour){
                $timearr = array(); //置空
                $i = $hours;
                while(true){
                    $nend = $start + $i*$onehour;
                    $nstart = $start + ($i-$hours)*$onehour;
                    $timearr[] = array(
                        'start_time' => date('Y-m-d H:i',$nstart),
                        'end_time' => date('Y-m-d H:i',$nend),
                    );
                    if($nend >= $end){
                        break;
                    }
                    $i += $hours;
                }
            }
        }

        if($days > 0){
            $timearray = $timearr;
            for ($i=1; $i<=$days;$i++){
                foreach ($timearray as $k=>$v){
                    $timearr[] = array(
                        'start_time' => date('Y-m-d H:i',strtotime($v['start_time']) + $i*$oneday),
                        'end_time' => date('Y-m-d H:i',strtotime($v['end_time']) + $i*$oneday),
                    );
                }
            }
        }
        return $timearr;
    }

    //获取巡查计划任务
    public function getTaskOne($taskId){
        $ret=Db::name('device_task')->where('id',$taskId)->find();
        //获取计划任务检查组id
        $old_addrs=Db::name('device_task_addr')
            ->where('task_id',$ret['id'])->select();
        foreach ($old_addrs as $k=>$v){
            $ids[$k]=$v['device_id'];
        }
        $ret['old_addrs']=$ids;
        //获取计划任务检查人员
        $old_user_ids = Db::name('device_task_user')->where('task_id',$ret['id'])->column('user_id');
//        foreach ($old_user_ids as $k=>$v){
//            $ids[$k]=$v['user_id'];
//        }

        $ret['old_user_ids']=$old_user_ids;
        return $ret;
    }

    //分组获取任务计划最近12个月份
    public function get_task_month($org_id){
        $list = $this
            ->field('create_yyyymm')
            ->group('create_yyyymm')
            ->where('org_id',$org_id)
            ->where('del',0)
            ->order('create_yyyymm','desc')
            ->limit(12)
            ->select();
        $list = $list?$list->toArray():array();
        foreach ($list as $k=>$v){
            $list[$k]['create_yyyymm'] = date('Y-m',strtotime($v['create_yyyymm'].'01'));
        }
        return $list;
    }

    //定时处理超时任务
    public function timer_action(){
        $curTime = date('Y-m-d H:i:s');
        $map[] = ['del','=',0];
        $map[] = ['status','in',[0,1]];
        $map[] = ['end_time','<',$curTime];
        $this->where($map)
            ->update(['status'=>3]);
        $ids = Db::name('task')
            ->alias('a')
            ->join('device_task b','a.bus_id=b.id')
            ->where('b.end_time','<',$curTime)
            ->where('a.type',(new Task())::TASK_TYPE_DEVICE)
            ->column('a.id');
        if(!empty($ids)){
            Db::name('task')
                ->where('id','in',$ids)
                ->delete();
        }
    }
    public function addDeviceTask(){
        $curTime = date('Y-m-d H:i:s',time()+12*60*60);
        $map[] = ['a.del','=',0];
        $map[] = ['a.status','=',0];
        $map[] = ['a.start_time','<',$curTime];

        $ids = $this
            ->alias('a')
            ->join('device_task_user b','b.task_id=a.id')
            ->where($map)
            ->field('a.*,b.user_id')
            ->select();
        if(!empty($ids)){
            $ids = $ids->toArray();
            $a = [];
            foreach ($ids as $k=>$v){
                $check = Db::name('task')
                    ->where('type',(new Task())::TASK_TYPE_DEVICE)
                    ->where('org_id',$v['org_id'])
                    ->where('bus_id',$v['id'])
                    ->where('user_id',$v['user_id'])
                    ->find();
                if(empty($check)){
                    $a[]= [
                        'org_id'=>$v['org_id'],
                        'type'=>(new Task())::TASK_TYPE_DEVICE,
                        'start_time'=>$v['start_time'],
                        'create_time'=>getTime(),
                        'bus_id'=>$v['id'],
                        'user_id'=>$v['user_id']
                    ];
                }
            }
            if(!empty($a)){
                Db::name('task')
                    ->insertAll($a);
            }
        }
    }

    public function get_list_by_time($orgId,$start,$end){

        $map[] = ['org_id','=',$orgId];
        $map[] = ['del','=',0];
        $map[] = ['start_time','<',$end];
        $map[] = ['end_time','>=',$start];

        $list = $this->field('id,title,start_time,end_time,status')
            ->where($map)
            ->select();
        $list = $list?$list->toArray():[];
        foreach ($list as $k=>$v){
            $userList = Db::name('device_task_user')
                ->alias('a')
                ->field('u.id,u.real_name')
                ->join('user u','u.id = a.user_id')
                ->where('a.task_id',$v['id'])
                ->column('real_name');
            $list[$k]['users'] = $userList?implode(',',$userList):'';
        }
        return $list?$list:array();
    }

    //复制任务
    public function plan_data($post,$org){ //TODO::已复制过的月份是否可以继续复制
        $from = strtotime($post['from'].'-01');
        $to = strtotime($post['to'].'-01');
        $max = strtotime(date('Y-m-d', strtotime($post['to'].'-01 +1 month')));
        $cha = $to - $from;

        $map[] = ['del','=',0];
        $map[] = ['org_id','=',$org];
        $map[] = ['create_yyyymm','=',date('Ym',strtotime($post['from'].'-01'))];
        $list = $this->where($map)->select();
        if(!$list){
            $this->error = '要复制的月份下没有任务';
            return false;
        }
        $list = $list->toArray();
        $this->startTrans();
        try{
            $uuid = '';
            while (true) {
                $uuid = new_guid();
                $ret = $this
                    ->where('uuid',$uuid)
                    ->find();
                if(!$ret){
                    break;
                }
            }
            foreach ($list as $k=>$v){
                $start_time = strtotime($v['start_time'])+$cha;
                if($start_time >= $max){
                    continue;
                }
                $v['start_time'] = date('Y-m-d H:i:s',$start_time);
                $v['end_time'] = date('Y-m-d H:i:s',strtotime($v['end_time'])+$cha);
                $v['uuid'] = $uuid;
                $ret = $this->copy_one($v);
                if(!$ret){
                    \exception('复制失败');
                }
            }
            Db::commit();
            return true;
        }catch (Exception $e){
            $this->error = $e->getMessage();
            Db::rollback();
            return false;
        }
    }

    //复制单个任务
    private function copy_one($data){
        $id = $data['id'];
        unset($data['id']);
        $data['status'] = 0;
        $data['create_time'] = date('Y-m-d H:i:s');
        $data['create_yyyymm'] = date('Ym',strtotime($data['start_time']));
        $data['create_yyyy'] = date('Y',strtotime($data['start_time']));
        $data['create_yyyymmdd'] = date('Ymd',strtotime($data['start_time']));
        $addrs = $this->get_task_addr($id);
        $userids = $this->get_task_user($id);

        //添加任务
        $taskid = $this->insertGetId($data);
        if(!$taskid){
            return false;
        }

        //添加检查地点
        $addr = array();
        foreach ($addrs as $k=>$v){
            $addr[] = array(
                'task_id' => $taskid,
                'device_id' => $v
            );
        }
        $res = Db::name('device_task_addr')->insertAll($addr);
        if(!$res){
            return false;
        }

        //添加检查人员
        $user = array();
        foreach ($userids as $k=>$v){
            $user[] = array(
                'task_id' => $taskid,
                'user_id' => $v
            );
        }
        $res = Db::name('device_task_user')->insertAll($user);
        if(!$res){
            return false;
        }
        return true;
    }

    //获取任务检查地点
    public function get_task_addr($taskid){
        $addrlist = Db::name('device_task_addr')
            ->where('task_id',$taskid)
            ->column('device_id');
        return $addrlist;
    }

    //获取任务检查人员
    public function get_task_user($taskid){
        $userlist = Db::name('device_task_user')
            ->where('task_id',$taskid)
            ->column('user_id');
        return $userlist;
    }

    public function del($id,$userId){
        try{
            $ret = Db::name('device_task')->where('id',$id)->update([
                'del' => 1,
                'del_user_id' => $userId,
                'del_time' => getTime()
            ]);
            if(!$ret){
                \exception('删除失败');
            }
            Db::name('task')
                ->where('bus_id', $id)
                ->where('type', (new Task())::TASK_TYPE_DEVICE)
                ->delete();
        }catch (\Exception $e){
            trace($e->getMessage());
            return false;
        }
        return true;
    }
    public function byIdSDel($ids,$userId){
        $list = Db::name('device_task')->where('id','in',$ids)
            ->where('status',1)
             ->select();

        if(!empty($list)){
           $this->error ='正在进行中的计划无法删除';
           return false;
        }
//        $ids = array_column($list,'id');
        try{
            $ret = Db::name('device_task')->where('id','in',$ids)->update([
                'del' => 1,
                'del_user_id' => $userId,
                'del_time' => getTime()
            ]);
            if(!$ret){
                \exception('删除失败');
            }
           Db::name('device_record')->whereIn('task_id',$ids)->delete();

            Db::name('task')
                ->where('bus_id','in', $ids)
                ->where('type', (new Task())::TASK_TYPE_DEVICE)
                ->delete();
            return true;
        }catch (\Exception $e){
            trace($e->getMessage());
            $this->error = $e->getMessage();
            return false;
        }
        return true;
    }
    public function batchDel($orgId,$userId){
        $data = request()->post();
        $minmonth = date('Y-m');
        if($minmonth >= $data['from']){
            $this->error = '当月任务不能删除';
            return false;
        }

        $where = array(
            'org_id' => $orgId,
            'del' => 0,
            'create_yyyymm' => date('Ym',strtotime($data['from'].'-01'))
        );
        $type = (new Task())::TASK_TYPE_DEVICE;
        // 检查是否存在任务栏数据中
        $dailyIds = Db::name('device_task')
            ->alias('dt')
            ->join('task t','t.bus_id = dt.id')
            ->where('t.type',$type)
            ->where('dt.org_id',$orgId)
            ->where('dt.del',0)
            ->where('dt.create_yyyymm',date('Ym',strtotime($data['from'].'-01')))
            ->column('dt.id');
        Db::startTrans();
        try{
            $default['del'] = 1;
            $default['del_user_id'] = $userId;
            $default['del_time'] = date('Y-m-d H:i:s');
            $result = Db::name('device_task')
                ->where($where)
                ->update($default);
            if(!$result){
                \exception('操作失败');
            }

            if($dailyIds){
                $ret = Db::name('task')
                    ->where('bus_id', 'in',implode(',',$dailyIds))
                    ->where('type', (new Task())::TASK_TYPE_DEVICE)
                    ->delete();
                if(!$ret){
                    \exception('操作失败');
                }
            }


            Db::commit();

            return true;
        }catch (\Exception $e){
            Db::rollback();
            return false;
        }

    }

    public function delayTask($taskId,$endTime,$reason,$userId,$orgId){
        if($taskId < 0){
            HelpHander::error('参数错误');
        }
        if(!$endTime || date('Y-m-d H:i',strtotime($endTime)) != $endTime){
            HelpHander::error('未选择延期时间');
        }
        if(strtotime($endTime) <= time()){
            HelpHander::error('延期时间必须大于当前时间');
        }
        if(!$reason){
            HelpHander::error('未填写延期原因');
        }
        $task = Db::name('device_task')->where('org_id',$orgId)->where('id',$taskId)->where('del',0)->find();
        if(!$task){
            HelpHander::error('参数错误');
        }
        if($task['status'] != 3){
            HelpHander::error('只有未完成的任务可申请延期');
        }
        $ret = Db::name('device_task_user')->where('task_id',$taskId)->where('user_id',$userId)->find();
        if(!$ret){
            HelpHander::error('无权限操作');
        }
        // 检测是否有正在审核中的延期申请
        $ret = Db::name('device_task_delay')->where('task_id',$taskId)->where('status',0)->find();
        if($ret){
            HelpHander::error('该任务已存在未处理的延期申请');
        }
        $ret = Db::name('device_task_delay')->insert([
            'org_id' => $orgId,
            'user_id' => $userId,
            'task_id' => $taskId,
            'end_time' => $endTime,
            'reason' => $reason,
            'status' => 0,
            'create_time' => date('Y-m-d H:i:s')
        ]);
        if(!$ret){
            HelpHander::error('操作失败');
        }
        return true;
    }

    public function cancelDelay($id,$userId){
        if($id < 0){
            HelpHander::error('参数错误');
        }
        $ret = Db::name('device_task_delay')->where('id',$id)->where('user_id',$userId)->find();
        if(!$ret){
            HelpHander::error('记录不存在');
        }
        if($ret['status'] != 0){
            HelpHander::error('申请已处理,无法取消');
        }

        $res = Db::name('device_task_delay')->where('id',$id)->update(['status'=>3,'update_time'=>date('Y-m-d H:i:s')]);
        if(!$res){
            HelpHander::error('操作失败');
        }
        return true;
    }

    public function delayLists($page,$size,$userId,$orgId){

        $record = Db::name('device_task_delay')
            ->where('user_id',$userId)
            ->where('org_id',$orgId)
            ->order('id desc')
            ->page($page,$size)
            ->select();
        $record = $record?$record:[];
        foreach ($record as $k=>$v){
            $taskTitle = Db::name('device_task')->where('id',$v['task_id'])->value('title');
            $record[$k]['task_title'] = $taskTitle?$taskTitle:'';
            $uname = Db::name('user')->where('id',$v['user_id'])->value('real_name');
            $record[$k]['uname'] = $uname?$uname:'';
            $dealUser = '';
            if($v['deal_user_id'] > 0){
                $dealUser = Db::name('user')->where('id',$v['deal_user_id'])->value('real_name');
            }
            $record[$k]['deal_user'] = $dealUser?$dealUser:'';
            $record[$k]['end_time'] = date('Y-m-d H:i',strtotime($v['end_time']));
            $record[$k]['update_time'] = $v['update_time']?$v['update_time']:'';
        }

        return $record;
    }

    public function dealDelay($userId,$orgId){
        $id = input('id/d',0);
        $status = input('status/d',0);
        $endTime = input('end_time','');
        $remark = input('remark','','trim');
        if(!in_array($status,[1,2]) || $id <= 0){
            $this->error = "参数错误";
            return false;
        }
        if($status == 1 && !$endTime){
            $this->error = "延期时间不能为空";
            return false;
        }
        $info = Db::name('device_task_delay')->where('id',$id)->where('org_id',$orgId)->find();
        if(!$info){
            $this->error = "记录不存在";
            return false;
        }
        if($info['status'] != 0){
            $this->error = "申请已处理";
            return false;
        }
        if($status == 1 && strtotime($endTime) <= time()){
            $this->error = "延期时间不能小于当前时间";
           // Db::name('device_task_delay')->where('id',$id)->update(['status'=>3,'update_time'=>date('Y-m-d H:i:s')]);
            return false;
        }

        Db::startTrans();
        try{
            $ret = Db::name('device_task_delay')->where('id',$id)->update([
                'deal_user_id'=>$userId,
                'status'=>$status,
                'remark'=>$remark,
                'end_time'=>$endTime,
                'update_time'=>date('Y-m-d H:i:s')
            ]);
            if(!$ret){
                \exception('操作失败');
            }

            if($status == 1){
                $task = Db::name('device_task')->where('id',$info['task_id'])->find();
                // 恢复计划任务
                $res = Db::name('device_task')->where('id',$info['task_id'])->update([
                    'status' => 1,
                    'del' => 0,
                    'end_time' => $info['end_time']
                ]);
                if(!$res){
                    \exception('操作失败');
                }

                $userIds = Db::name('device_task_user')->where('task_id',$info['task_id'])->column('user_id');
                $arr = [];
                foreach ($userIds as $v){
                    $arr[] = [
                        'org_id'=>$orgId,
                        'type'=>(new Task())::TASK_TYPE_DEVICE,
                        'start_time' => $task['start_time'],
                        'create_time'=>getTime(),
                        'bus_id'=>$task['id'],
                        'user_id'=>$v
                    ];
                }

                $res = Db::name('task')->insertAll($arr);
                if($res != count($userIds)){
                    \exception('操作失败');
                }
            }

            Db::commit();
        }catch (Exception $e){
            Db::rollback();
            $this->error = $e->getMessage();
            return false;
        }
        return true;
    }
    public function copyTask($data){
        $ret = $this->copy_one($data);
        return $ret;
    }
}