<?php
namespace App\Service;

use Maatwebsite\Excel\Facades\Excel;
use Illuminate\Support\Facades\Log;
use App\Models\StrategyExcel;
use App\Models\StrategySet;
use App\Models\StrategyTask;
use App\Jobs\StrategyTaskJob;
use App\Http\Controllers\Tool;

class StrategyService
{
    use Tool;
    //验证上传的excel
    public function validUploadExcel($request,$inputName,$maxUploadSize=''){
        $path = storage_path()."/import/";
        $path = str_replace('\\','/',$path);
        
        $extension = $request->file($inputName)->getClientOriginalExtension();
        if($extension != 'xlsx' && $extension != 'xls' ){
            return ['msg'=>'非xls及xlsx格式文件', 'code'=>401];
        }
        if (!empty($maxUploadSize)){//限制最大上传文件（字节）
            $size = $request->file($inputName)->getClientSize();
            if ($size > $maxUploadSize){
                return ['msg'=>'上传文件过大', 'code'=>401];
            }
        }
        
        $fileName = date('YmdHis',time()).'.xlsx';
        
        if($request->hasFile($inputName)){
            if($request->file($inputName)->isValid()){
                $upr = $request->file($inputName)->move($path,$fileName);
                if (!$upr){
                    return ['msg'=>'文件上传失败', 'code'=>401];
                }else{
                    $res = [];
                    Excel::load($path.'/'.$fileName,function($reader) use( &$res ){
                        $reader = $reader->getSheet(0);
                        $res = $reader->toArray();
                    });
                        $data = array_filter($res);
                        if (count($data) > 1001){
                            return ['msg'=>'条数超过1000条', 'code'=>401];
                        }
                        //验证excel表头格式
                        $title = array_shift($data);
                        if ($title != ['姓名','*手机号码','值班日期']){//匹配excel表头
                            Log::channel('api')->info('表头不一致：导入的表头：'.implode('#', $title)." ；正确的表头数据：".implode("#", ['姓名','*手机号码','值班日期']));
                            return ['msg'=>'导入失败，excel表头不一致', 'code'=>401];
                        }                        
                        return $data;
                }
            }
        }
        return ['msg'=>'excel处理失败', 'code'=>401];
    }
    //判断excel数据问题,$day_type//外呼日期类型 0每天 1日期前一天和当天   1需要验证值班日期必填
    public function validExcelData($successData,$day_type){
        $failData = [];
        $total = count($successData);
        foreach ($successData as $k=>$v){
            $dataLab = 1;
            if (strlen($v[0]) > 20){ //姓名最大20个字符，中文处理，放入失败数据中
                array_push($v, "姓名过长");  
                $failData[] = $v;
                $dataLab = 0;
            }
            if ($dataLab == 1 && !preg_match('/^1[3-8]{1}[0-9]{9}$/', $v[1])){//手机号格式验证（手机号码验证以13、14、15、16、17、18开头的11位数字），不能为空
                array_push($v, "手机号格式不正确"); 
                $failData[] = $v;
                $dataLab = 0;
            }
            if ($dataLab == 1 && $day_type == 1){//验证必填且为日期格式
                if (empty($v[2])){
                    array_push($v, "值班日期必填"); 
                    $failData[] = $v;
                    $dataLab = 0;
                }else{
                    $unixTime = strtotime($v[2]);
                    if (!$unixTime || (date('Y/n/j', $unixTime) != $v[2] && date('n/j/Y', $unixTime) != $v[2])) { //月日不带0（2020/5/3或者 5/3/2020）
                        array_push($v, "值班日期格式错误");
                        $failData[] = $v;
                        $dataLab = 0;
                    }else{
                        $v[2] = date('Y-m-d',$unixTime); //处理存储db的日期格式（2020-05-13）
                        $successData[$k] = $v;
                    }
                    
                }
            }else{//不需要验证附初始值
                $successData[$k][2] = date('Y-m-d');
            }
            if ($dataLab == 0){
                unset($successData[$k]);
            }
        }
        
        $failTotal = count($failData);
        $successTotal = count($successData);
        $failDataFile = '';
        if ($failTotal > 0){//把导出错误数据存入excel表格中供下载
            $failDataTitle = ['姓名','*手机号码','值班日期','失败原因'];
            array_unshift($failData, $failDataTitle);
            $failExcelName = "导入失败数据_".date('YmdHis');
            //dump($failExcelName);
            $failFile = $this->storeExcelStyle($failExcelName, $failData,'','import');
            //$failDataFile = $failExcelName.'.xlsx';
            if ($failFile){
                $failDataFile = $failExcelName;
            }else{ //失败数据写入失败
                Log::channel('api')->error('错误文件excel写入失败');
            }
        }
        return compact('successData','total','failData','failTotal','successTotal','failDataFile');
    }
    
    
    
    //保存内容到excel文件并下载,$exportType  excel文件操作类型  0存储数据直接保存， 1直接导出数据 ， 2保存并导出数据
    public function storeExcelStyle($excelName,$datas,$endLen='',$path='',$exportType=0){
        try{
            $arr = range('A','Z');
            if (!empty($endLen)){
                $endLen = $endLen - 1;
                if(isset($arr[$endLen])){
                    $arr = range('A',$arr[$endLen]);
                }
            }
            
            $e = Excel::create(iconv('UTF-8', 'GBK', $excelName),function($excel) use ($datas,$arr){
                $excel->sheet('score', function($sheet) use ($datas,$arr){
                    $col =array();
                    $sheet->rows($datas);
                    foreach($arr as $v){
                        $col[$v]=12;
                    }
                    $sheet->setWidth($col);                    
                    foreach ($arr as $k=> $v){
                        $objRichText = new \PHPExcel_RichText();
                        if(!empty($datas[0][$k])){
                            if (strpos($datas[0][$k], '*') === 0){
                                $objPayable = $objRichText->createTextRun('*');
                                $objPayable->getFont()->setColor( new \PHPExcel_Style_Color( \PHPExcel_Style_Color::COLOR_RED ) );//设置颜色
                            }
                            $objRichText->createText(ltrim($datas[0][$k],'*'));
                            $sheet->setCellValue($arr[$k].'1',$objRichText);
                        }
                        
                    }
                    
                });
            });
            
            if ($exportType == 1){
                if (empty($path)){//默认路径storage/exports
                    $e->export('xlsx');
                }else{//自定义路径 storage/$path
                    $e->export('xlsx', storage_path($path));
                }
            }elseif ($exportType == 2){
                if (empty($path)){//默认路径storage/exports
                    $e->store('xlsx')->export('xlsx');
                }else{//自定义路径 storage/$path
                    $e->store('xlsx', storage_path($path))->export('xlsx', storage_path($path));
                }
            }else{
                if (empty($path)){//默认路径storage/exports
                    $e->store('xlsx');
                }else{//自定义路径 storage/$path
                    $e->store('xlsx', storage_path($path));
                }
            }
            
            
            return true;
        }catch(\Exception $e){
            Log::channel('api')->error($e->getFile().'-'.$e->getLine().'-'.$e->getMessage());
            return false;
        }
    }
    
    //添加策略处理excel数据入库
    public function insertStrategyExcel($strategySn,$data){
        if (count($data) > 0){
            $insertData = [];
            $now = date('Y-m-d H:i:s');
            foreach ($data as $k=>$v){
                $insertTemp = [];
                $insertTemp['strategy_sn'] = $strategySn;
                $insertTemp['name'] = $v[0] == null ? '' : $v[0];
                $insertTemp['phone'] = (int)$v[1];
                $insertTemp['duty_date'] = $v[2] == null ? '' : $v[2];
                $insertTemp['created_at'] = $now;
                $insertTemp['updated_at'] = $now;
                $insertData[] = $insertTemp;
            }
            //dd($insertData);
            $insertExcelReturn = StrategyExcel::insert($insertData);   
            if ($insertExcelReturn){//创建任务数据，这一步剥离出来，不然接口返回太慢，方案==，使用队列处理
                $jobParams = ['strategySn'=>$strategySn];
                // /opt/lampp/bin/php /opt/lampp/xiaoa/xiaoa-aic/artisan queue:work --queue=StrategyTask --sleep=3 --tries=0 --daemon --timeout=90
                $job = (new StrategyTaskJob($jobParams))->onQueue('StrategyTask');
                dispatch($job);
                //$this->createTaskDataJob($strategySn);
                return true;
            }
        }
        return false;
    }
    
    //跟进策略任务数据生成待新建任务的excel数据,（两种情况 一、有新数据时当时生成，二、每月1号生成）$operaterType类型 1为每月1号生成，0是按照当前日期计算
    public function createTaskDataJob($strategySn){
        //set_time_limit(0);
        
        if (empty($strategyInfo)){
            $strategyInfo = StrategySet::where('strategy_sn',$strategySn)->first()->toArray();
        }        
        $cmonth = date('n');//当前月份（不带0）
        $data = StrategyExcel::where([['strategy_sn',$strategySn],['last_handle_month','<>',$cmonth]])->get();
        $batch = 500; //单批处理多少条
        $total = count($data);
        $now = date('Y-m-d H:i:s');
        $taskData = [];
        //一天呼叫两次类型，拆分时间，拆分项目
        $call_time = explode("#", $strategyInfo['call_time_set']);
        $project_sn = explode("#", $strategyInfo['project_sn']);
        
        $tempi = 0;        
        ////每天、一天两次，两个时间点、一个话术或者两个话术；日期前一天和当天、一天一次， 一个时间点两个话术
        if ($strategyInfo['day_type'] == 0 && $strategyInfo['frequency_type'] == 2){//每天拨打，一天两次       
            $doubleTotal = $total*2;
            $startDay = date('Y-m-d'); //执行当天时间            
            //这个月最后一天日期
            $endDay = date('Y-m-d',strtotime("-1 day",strtotime("+1 month",strtotime(date('Y-m-01')))));
            $day = date('j',strtotime($endDay)) - date('j') + 1;
            $doubleTotal = $doubleTotal*$day;
            for ($i=$startDay;$i<=$endDay;$i=date("Y-m-d",strtotime("+1 day",strtotime($i)))){
                foreach ($data as $k=>$v){
                    $tempi = $tempi+2;
                    $taskData[] = [
                        'strategy_sn'=>$strategySn,
                        'name'=>$v->name,
                        'phone'=>$v->phone,
                        'duty_date'=>$v->duty_date,
                        'import_date'=>$v->created_at,
                        'parent_sn'=>$strategyInfo['parent_sn'],
                        'call_number'=>$strategyInfo['call_number'],
                        'project_sn'=>$project_sn[0],//$strategyInfo['project_sn'],
                        'user_sn'=>$strategyInfo['user_sn'],
                        'call_date'=>$i,
                        'call_time'=>$call_time[0],//$strategyInfo['call_time'],
                        'created_at'=>$now
                    ];
                    
                    $taskData[] = [
                        'strategy_sn'=>$strategySn,
                        'name'=>$v->name,
                        'phone'=>$v->phone,
                        'duty_date'=>$v->duty_date,
                        'import_date'=>$v->created_at,
                        'parent_sn'=>$strategyInfo['parent_sn'],
                        'call_number'=>$strategyInfo['call_number'],
                        'project_sn'=>isset($project_sn[1]) ? $project_sn[1] : $project_sn[0],
                        'user_sn'=>$strategyInfo['user_sn'],
                        'call_date'=>$i,
                        'call_time'=>isset($call_time[1]) ? $call_time[1] : $call_time[0],
                        'created_at'=>$now
                    ];
                    
                    if(count($taskData) == $batch || $doubleTotal == $batch || $tempi == $doubleTotal){
                        if (!empty($taskData)){
                            StrategyTask::insert($taskData);
                            $taskData = [];
                        }
                    }
                    
                }
            }
        }else{
           
            foreach ($data as $k=>$v){
                $tempi = $tempi+1;                
                $yesterday = date('Y-m-d',strtotime("-1 day",strtotime($v->duty_date)));
                $taskData[] = [
                    'strategy_sn'=>$strategySn,
                    'name'=>$v->name,
                    'phone'=>$v->phone,
                    'duty_date'=>$v->duty_date,
                    'import_date'=>$v->created_at,
                    'parent_sn'=>$strategyInfo['parent_sn'],
                    'call_number'=>$strategyInfo['call_number'],
                    'project_sn'=>$project_sn[0],
                    'user_sn'=>$strategyInfo['user_sn'],
                    'call_date'=>$yesterday,
                    'call_time'=>$call_time[0],
                    'created_at'=>$now
                ];
                $taskData[] = [
                    'strategy_sn'=>$strategySn,
                    'name'=>$v->name,
                    'phone'=>$v->phone,
                    'duty_date'=>$v->duty_date,
                    'import_date'=>$v->created_at,
                    'parent_sn'=>$strategyInfo['parent_sn'],
                    'call_number'=>$strategyInfo['call_number'],
                    'project_sn'=>isset($project_sn[1]) ? $project_sn[1] : $project_sn[0],
                    'user_sn'=>$strategyInfo['user_sn'],
                    'call_date'=>$v->duty_date,
                    'call_time'=>$call_time[0],
                    'created_at'=>$now
                ];
                if(count($taskData) == $batch || $total == $batch || $tempi == $total){
                     if (!empty($taskData)){
                         StrategyTask::insert($taskData);
                         $taskData = [];
                     }
                }
            }
        }
        //将处理的策略月份修改为最新
        StrategyExcel::where([['strategy_sn',$strategySn],['last_handle_month','<>',$cmonth]])->update(['last_handle_month'=>$cmonth]);
        $this->createdTask($strategySn);    //批量新建任务 
        $this->createdTask($strategySn);    //批量新建任务 
        $this->createdTask($strategySn);    //批量新建任务 
        $this->createdTask($strategySn);    //批量新建任务 
    }
    
    //创建任务
    public function createdTask($strategySn=''){
        $userInfo = $this->getAllowLoginUser();
        $today = date('Y-m-d');
        $whereArr = [['is_created',0],['call_date',$today],['created_fail_number','<=','3']];
        if (empty($strategySn)){
            array_push($whereArr, ['strategy_sn',$strategySn]);
        }
        $taskInfo = StrategyTask::where($whereArr)->get()->toArray(); //获取当天需要新建任务的数据
        $url = "https://test117.ciopaas.com/api/addJsonNoLogin";
        if (empty($taskInfo)){ //没有需要处理的数据
            return true;
        }
        foreach ($taskInfo as $k=>$v){//批量调用接口新建任务
            $failLabTemp = 0;
            $failReason = '';
            //处理参数
            if (empty($v['project_sn'])){
                break;
            }
            $client_info_json = [
                [
                    '姓名'=>$v['name'],
                    '电话'=>$v['phone'],
                    '地址'=>'',
                    '公司名称'=>'',
                    '备注'=>'',
                    '手机号码'=>$v['phone'],
                    '值班日期'=>$v['duty_date']
                ]
            ];
            $v['user_sn'] = trim($v['user_sn']);
            $v['project_sn'] = trim($v['project_sn']);
            $v['call_number'] = trim($v['call_number']);
            $params = [
                'user_sn'=>$v['user_sn'],
                'project_sn'=>$v['project_sn'],
                'source'=>date('YmdHis').$k, //任务名称，年月日时分秒，加上循环键值避免重复任务名
                'ai_user_sn'=>$v['user_sn'],//$v['user_sn'],
                'is_zidong'=>'off',//是否自动启动，否，任务定时启动
                'is_open_remove_duplication'=>'0',
                'is_auto_fail_recall'=>'1', //是否自动重呼，是
                'total_fail_recall_times'=>'3', //重呼次数
                'fail_recall_interval'=>'3',//重呼间隔时间
                'recall_auto'=>'1', //重呼方式； 0新建任务1原任务重呼
                'mark'=>'值班策略创建任务',
                'fail_recall_of_reason'=>'关机,来电提醒,稍后再拨,停机,无法接通,正在通话中,用户正忙,用户拒接,欠费,无人应答,其他,对方示忙',
                'is_auto_stop'=>'2', //0非自动暂停，1自动暂停 2 定时启动任务
                'timed_started_at'=>$v['call_date'].' '.$v['call_time'], //定时启动
                'yd_display_phone'=>$v['user_sn'].'@vos:'.$v['call_number'] //主叫号码传输格式
                //'ai_distribution_type'=>'0'//0公用ai 1按主账号分配ai（6.2人工外呼分配方式 0平均，1抢拨）
            ];
            
            $params['url'] = substr(md5(json_encode($params)),7,15);
            
            $params['client_info_json'] = json_encode(['data'=>$client_info_json]);
            
            $requestReturn = $this->requestPost($url,$params);
            
            $requestReturnArr = json_decode($requestReturn,true);
            if (isset($requestReturnArr['code'])){
                if ($requestReturnArr['code'] == 0){//接口请求返回成功
                    if ($requestReturnArr['data']['total'] == $requestReturnArr['data']['success']){//全部成功
                        StrategyTask::where('id',$v['id'])->update(['is_created'=>1]); //设为已创建
                    }else{//存在失败数据
                        $failLabTemp = 1;
                        $failReason = substr($requestReturnArr['msg'],0,490);
                    }
                }else{ //接口请求返回异常
                    $failLabTemp = 1;
                    $failReason = substr($requestReturnArr['msg'],0,490);
                }
            }else{
                $failLabTemp = 1;
                $failReason = substr($requestReturn,0,490);
            }
            
            if ($failLabTemp == 1){
                StrategyTask::where('id',$v['id'])->update(['created_fail_number'=>($v['created_fail_number'] + 1),'create_fail_reason'=>$failReason]); //设为已创建
            }
        }
        return true; //操作结束标识
    }
    
}

