<?php
namespace app\mobile\controller;

use think\facade\Db;
use think\facade\Filesystem;

/** 沿用旧状态：1待处理，2待班长确认，3已关闭，0撤销。 */
class OmsCheckIssue extends OmsToolsCheck
{
    private $issueMaps;
    private $latestLogs=[];
    private function prepareIssues($rows) {
        $this->issueMaps=[];$this->issueMaps['me_check_issue']=array_column($rows,null,'id');
        $records=Db::name('me_check_record')->whereIn('id',array_column($rows,'check_id') ?: [-1])->select()->toArray();$this->issueMaps['me_check_record']=array_column($records,null,'id');
        $this->issueMaps['me_machine_list']=Db::name('me_machine_list')->whereIn('id',array_column($records,'m_id') ?: [-1])->column('*','id');
        $this->issueMaps['me_check_list']=Db::name('me_check_list')->whereIn('id',array_column($records,'check_id') ?: [-1])->column('*','id');
        $this->issueMaps['me_check_issue_flow']=Db::name('me_check_issue_flow')->whereIn('issue_id',array_column($rows,'id') ?: [-1])->column('*','issue_id');
        $this->issueMaps['team_list']=Db::name('team_list')->whereIn('id',array_column($rows,'tid') ?: [-1])->column('*','id');
        $this->issueMaps['admin_user']=Db::name('admin_user')->column('id,truename,status,job','id');
        $this->issueMaps['member_list']=Db::name('member_list')->whereIn('id',array_column($rows,'mid') ?: [-1])->column('id,ename','id');
        $this->issueMaps['team_base']=Db::name('team_base')->column('id,title','id');
        $this->latestLogs=[];foreach(Db::name('me_check_issue_log')->whereIn('issue_id',array_column($rows,'id') ?: [-1])->where('action','<>','保存草稿')->order('id')->select()->toArray() as $log)$this->latestLogs[$log['issue_id']]=$log;
    }
    private function lookup($table,$id) { return $this->issueMaps!==null?($this->issueMaps[$table][$id]??null):Db::name($table)->find($id); }
    protected function issueData($id) {
        $row=$this->lookup('me_check_issue',$id);if(!$row)$this->fail('异常不存在',404);
        $record=$this->lookup('me_check_record',$row['check_id']);$machine=$record?$this->lookup('me_machine_list',$record['m_id']):null;
        $flow=$this->lookup('me_check_issue_flow',$id) ?: ['issue_id'=>$id,'version'=>0,'draft'=>'','images'=>'[]','updated_at'=>0,'confirmed_by'=>0,'confirmed_at'=>0];
        $team=$this->lookup('team_list',$row['tid']);$clause=$record?$this->lookup('me_check_list',$record['check_id']):null;
        // owner仅记录实际提交反馈的人，不再用于分配或控制权限。
        $owner=(int)$row['update']>0?(int)$row['owner']:0;
        return ['row'=>$row,'record'=>$record,'machine'=>$machine,'flow'=>$flow,'team'=>$team,'clause'=>$clause,'owner'=>$owner,'version'=>hash('sha256',json_encode([$row,$flow]))];
    }
    protected function issuePermissions($a,$d) {
        $admin=$this->adminIdentity($a);$member=$this->memberIdentity($a);$aid=(int)($admin['id']??0);$manager=$this->isManager($a);$engineer=$admin && (int)$admin['dpt']===2;$row=$d['row'];$leader=$aid>0 && $d['team'] && (int)$d['team']['aid']===$aid;
        return ['canView'=>$engineer || $manager || $leader || ($member && (int)$row['mid']===(int)$member['id']), 'canFeedback'=>$engineer && (int)$row['status']===1,'canConfirm'=>$leader && (int)$row['status']===2,'canAssign'=>false,'canCancel'=>$leader && in_array((int)$row['status'],[1,2],true),'isLeader'=>$leader,'isManager'=>$manager];
    }
    protected function presentIssue($a,$d,$full=false) {
        $r=$d['row'];$f=$d['flow'];$m=$d['machine'];$record=$d['record'];$p=$this->issuePermissions($a,$d);$status=(int)$r['status'];$images=json_decode($f['images'],true) ?: [];
        $item=['id'=>(int)$r['id'],'status'=>$status,'statusName'=>[0=>'已撤销',1=>'待处理',2=>'待确认',3=>'已关闭'][$status]??'历史状态','deviceId'=>(int)($m['id']??0),'deviceName'=>$m['m_name']??'设备资料缺失','asset'=>(string)($m['fixed_number']??''),'lineId'=>(int)($m['line']??0),'lineName'=>$m?(($this->lookup('team_base',$m['line'])['title']??'') ?: ''):'','description'=>(string)(($status===0 ? (Db::name('me_check_issue_log')->where(['issue_id'=>$r['id'],'action'=>'上报异常'])->order('id')->value('note')) : null) ?? ($record['mark']??'历史点检记录缺失，请核对原始数据')),'content'=>(string)($d['clause']['content']??''),'standard'=>(string)($d['clause']['standard']??''),'method'=>(string)($d['clause']['method']??''),'reporter'=>($this->lookup('member_list',$r['mid'])['ename']??'') ?: '历史点检人','teamId'=>(int)$r['tid'],'teamName'=>$d['team']['team']??'历史班组','ownerId'=>$d['owner'],'ownerName'=>$d['owner']?(($this->lookup('admin_user',$d['owner'])['truename']??'') ?: ''):'尚未反馈','confirmName'=>($this->lookup('admin_user',$d['team']['aid']??0)['truename']??'') ?: '班长未设置','createdAt'=>date('Y-m-d H:i',(int)$r['check_time']),'waitDays'=>max(0,(int)floor(($this->now()-(int)$r['check_time'])/86400)),'feedback'=>(string)$r['mark'],'feedbackAt'=>$r['update']?date('Y-m-d H:i',(int)$r['update']):'','draft'=>$p['canFeedback']?(string)$f['draft']:'','images'=>array_map(function($path){return ['path'=>$path,'url'=>'https://www.cqoms.com'.$path];},$images),'confirmedAt'=>$f['confirmed_at']?date('Y-m-d H:i',$f['confirmed_at']):'','version'=>$d['version'],'canFeedback'=>$p['canFeedback'],'canConfirm'=>$p['canConfirm'],'canAssign'=>$p['canAssign'],'canCancel'=>$p['canCancel']];
        if($full)$item['history']=Db::name('me_check_issue_log')->where('issue_id',$r['id'])->field('id,actor,action,note,created_at')->order('id desc')->select()->toArray();
        return $item;
    }
    public function options() {
        return $this->guarded(function(){
            $this->requireMethod('GET');$a=$this->current();$admin=$this->adminIdentity($a);$manage=$this->isManager($a);$isLeader=$admin && Db::name('team_list')->where(['aid'=>$admin['id'],'status'=>1])->count()>0;
            $owners=Db::name('admin_user')->where(['status'=>1,'dpt'=>2])->where('job','<>',79)->field('id,truename')->order('truename,id')->select()->toArray();
            return $this->result(['canManage'=>$manage,'canConfirm'=>(bool)$isLeader,'canProcess'=>(bool)($admin && (int)$admin['dpt']===2),'owners'=>$owners]);
        });
    }
    public function records() {
        return $this->guarded(function(){
            $this->requireMethod('GET');$a=$this->current();$scope=$this->request->get('scope','all');if(!in_array($scope,['process','confirm','reported','handled','mine','all'],true))$this->fail('列表类型不正确');
            $member=$this->memberIdentity($a);$admin=$this->adminIdentity($a);$aid=(int)($admin['id']??0);$handled=$aid?Db::name('me_check_issue_log')->where('auth_id',$a['id'])->whereNotIn('action',['上报异常','保存草稿'])->column('issue_id'):[];$kw=$this->request->get('keyword','');if(!is_string($kw)||mb_strlen($kw)>50)$this->fail('搜索文字过长');$date=$this->request->get('date','');$timestamp=$date?$this->dateValue($date):0;$state=$this->request->get('status','');$line=(int)$this->request->get('lineId',0);$owner=(int)$this->request->get('ownerId',0);$project=(int)$this->request->get('projectId',0);$items=[];
            $rows=Db::name('me_check_issue')->order('id desc')->select()->toArray();$this->prepareIssues($rows);
            foreach($rows as $r){$d=$this->issueData($r['id']);$p=$this->issuePermissions($a,$d);if(!$p['canView'] && !(in_array($scope,['handled','mine'],true) && in_array((int)$r['id'],array_map('intval',$handled),true)))continue;
                if($scope==='process'&&!$p['canFeedback'])continue;if($scope==='confirm'&&!$p['canConfirm'])continue;if($scope==='reported'&&(!$member || (int)$r['mid']!==(int)$member['id']))continue;if(in_array($scope,['handled','mine'],true) && !in_array((int)$r['id'],array_map('intval',$handled),true) && !($aid && (int)$r['owner']===$aid && (int)$r['status']>=2) && !($scope==='mine' && $member && (int)$r['mid']===(int)$member['id']))continue;
                if($project && (int)($d['team']['project']??0)!==$project)continue;
                if($state!=='' && (string)$r['status']!==(string)$state)continue;if($timestamp && ((int)$r['check_time']<$timestamp || (int)$r['check_time']>=$timestamp+86400))continue;if($line && (int)($d['machine']['line']??0)!==$line)continue;if($owner && $d['owner']!==$owner)continue;
                $item=$this->presentIssue($a,$d);if(trim($kw)!=='' && mb_stripos($item['deviceName'].' '.$item['asset'].' '.$item['description'].' '.$item['ownerName'],trim($kw))===false)continue;$items[]=$item;
            }
            $page=max(1,min(10000,(int)$this->request->get('page',1)));return $this->result(['items'=>array_slice($items,($page-1)*20,20),'total'=>count($items),'page'=>$page]);
        });
    }
    public function detail() {
        return $this->guarded(function(){
            $this->requireMethod('GET');$a=$this->current();$d=$this->issueData($this->number($this->request->get('id')));$p=$this->issuePermissions($a,$d);$handled=Db::name('me_check_issue_log')->where(['auth_id'=>$a['id'],'issue_id'=>$d['row']['id']])->whereNotIn('action',['上报异常','保存草稿'])->count();if(!$p['canView']&&!$handled)$this->fail('无权查看此异常',403);return $this->result($this->presentIssue($a,$d,true));
        });
    }
    public function upload() {
        return $this->guarded(function(){
            $this->requireMethod('POST');$a=$this->current();$id=$this->number($this->request->post('id'));$d=$this->issueData($id);if(!$this->issuePermissions($a,$d)['canFeedback'])$this->fail('当前异常不能上传处理图片',403);
            $file=$this->request->file('image');if(!$file instanceof \think\file\UploadedFile || !$file->isValid() || $file->getSize()>5*1024*1024)$this->fail('请选择不超过5MB的图片');$types=['image/jpeg'=>'jpg','image/png'=>'png','image/webp'=>'webp'];$mime=$file->getMime();if(!isset($types[$mime])||!@getimagesize($file->getPathname()))$this->fail('请选择JPG、PNG或WebP图片');
            $ref=bin2hex(random_bytes(24));$path=Filesystem::disk('public')->putFileAs('wx_upload/check_issue/'.date('Ymd'),$file,$ref.'.'.$types[$mime]);if(!$path)$this->fail('图片保存失败');$url='/storage/'.str_replace('\\','/',$path);
            try{$this->cache()->set($this->cacheKey('check-image:'.$ref),['authId'=>(int)$a['id'],'issueId'=>$id,'path'=>$url],86400);}catch(\Throwable $e){Filesystem::disk('public')->delete($path);throw $e;}
            return $this->result(['reference'=>$ref]);
        });
    }
    protected function actionIssue($action) {
        $this->requireMethod('POST');$a=$this->current();$id=$this->number($this->request->post('id'));$initial=$this->issueData($id);$device=(int)($initial['record']['m_id']??0);
        $refs=[];$result=$this->lockDevice($device ?: 'issue-'.$id,function()use($a,$id,$action,&$refs){return Db::transaction(function()use($a,$id,$action,&$refs){
            $d=$this->issueData($id);$p=$this->issuePermissions($a,$d);if(!$p['canView'])$this->fail('无权处理此异常',403);if($this->request->post('version')!==$d['version'])$this->fail('异常已变化，请刷新后重试',409);
            $r=$d['row'];$f=$d['flow'];$row=[];$flow=[];$note='';
            if($action==='feedback'){
                if(!$p['canFeedback'])$this->fail('仅工程人员可填写待处理异常的处理结果',403);$mode=$this->request->post('mode');if(!in_array($mode,['save','submit'],true))$this->fail('提交方式不正确');$note=$this->textValue($this->request->post('feedback',''),false);
                $keep=$this->request->post('retainedPaths',[]);$uploads=$this->request->post('uploads',[]);$existing=json_decode($f['images'],true) ?: [];if(!is_array($keep)||!is_array($uploads)||count($keep)+count($uploads)>3 || count(array_unique($keep))!==count($keep))$this->fail('最多保留3张图片');foreach($keep as $path)if(!is_string($path)||!in_array($path,$existing,true))$this->fail('保留图片不属于该异常');
                foreach($uploads as $ref){if(!is_string($ref)||!preg_match('/^[a-f0-9]{48}$/',$ref)||isset($refs[$ref]))$this->fail('图片引用不正确');$img=$this->cache()->get($this->cacheKey('check-image:'.$ref));if(!$img || $img['authId']!==(int)$a['id'] || $img['issueId']!==$id)$this->fail('图片已失效，请重新选择');$keep[]=$img['path'];$refs[$ref]=true;}
                $flow=['draft'=>$note,'images'=>json_encode($keep)];$row=[];if($mode==='submit'){$row=['owner'=>(int)$a['admin_id']]+['mark'=>$note,'status'=>2,'update'=>$this->now()];$flow['draft']='';}
            }elseif($action==='confirm'){
                if(!$p['canConfirm'])$this->fail('仅点检班组班长可确认待验收异常',403);$note=$this->textValue($this->request->post('note',''),false);$row=['status'=>3];$flow=['confirmed_by'=>(int)$a['admin_id'],'confirmed_at'=>$this->now()];
            }elseif($action==='reject'){
                if(!$p['canConfirm'])$this->fail('仅点检班组班长可退回待验收异常',403);$note=$this->textValue($this->request->post('note'));$row=['status'=>1];$flow=['draft'=>(string)$r['mark']];
            }elseif($action==='cancel'){
                if(!$p['canCancel'])$this->fail('仅点检班组班长可撤销未关闭异常',403);$note=$this->textValue($this->request->post('note'));$row=['status'=>0];
                if(!$d['record'])$this->fail('原始点检记录缺失，无法恢复正常',409);
                if(!Db::name('me_check_issue_log')->where(['issue_id'=>$id,'action'=>'上报异常'])->count())Db::name('me_check_issue_log')->insert(['issue_id'=>$id,'auth_id'=>0,'actor'=>'历史记录','action'=>'上报异常','note'=>(string)$d['record']['mark'],'created_at'=>(int)$r['check_time']]);
                Db::name('me_check_record')->where('id',$r['check_id'])->update(['result'=>1,'mark'=>'误报已撤销，恢复正常']);
            }
            if($row)Db::name('me_check_issue')->where('id',$id)->update($row);$flow+=['version'=>(int)$f['version']+1,'updated_at'=>$this->now()];if((int)$f['version'])Db::name('me_check_issue_flow')->where('issue_id',$id)->update($flow);else Db::name('me_check_issue_flow')->insert($flow+['issue_id'=>$id,'draft'=>'','images'=>'[]']);
            $label=['feedback'=>$this->request->post('mode')==='save'?'保存草稿':'提交处理结果','confirm'=>'确认关闭','reject'=>'退回处理','cancel'=>'撤销异常'][$action];$person=$this->adminIdentity($a);Db::name('me_check_issue_log')->insert(['issue_id'=>$id,'auth_id'=>$a['id'],'actor'=>($person['truename']??'').' '.$a['username'],'action'=>$label,'note'=>$note,'created_at'=>$this->now()]);
            return $this->result($this->presentIssue($a,$this->issueData($id),true));
        });});
        foreach($refs as $ref=>$unused)try{$this->cache()->delete($this->cacheKey('check-image:'.$ref));}catch(\Throwable $e){\think\facade\Log::warning('check image cache cleanup failed');}
        return $result;
    }
    public function assign(){return $this->guarded(function(){$this->fail('异常由工程人员共同处理，无需分配',403);});}
    public function feedback(){return $this->guarded(function(){return $this->actionIssue('feedback');});}
    public function confirm(){return $this->guarded(function(){return $this->actionIssue('confirm');});}
    public function reject(){return $this->guarded(function(){return $this->actionIssue('reject');});}
    public function cancel(){return $this->guarded(function(){return $this->actionIssue('cancel');});}
    public function messageItems($account,$since,\app\mobile\service\MessageInbox $inbox) {
        if(!$inbox->allowsSource($this))$this->fail('接口不存在',404);$items=[];
        $aid=(int)($account['admin_id']??0);$notify=[];$projects=[];$allowed=[];
        foreach(Db::name('me_base')->whereIn('mid',[20,21])->select()->toArray() as $config){
            if((int)$config['mid']===20)$notify[]=(int)$config['title'];
            else $projects[(int)$config['mark']][]=$config;
        }
        $existing=Db::name('message')->where(['auth_id'=>$account['id'],'business'=>'check-issue'])->whereIn('state',['pending','notice'])->column('business_id');
        $recent=Db::name('me_check_issue_flow')->where('updated_at','>=',$since)->column('issue_id');
        $rows=Db::name('me_check_issue')->where(function($q)use($since,$recent,$existing){$q->whereIn('status',[1,2])->whereOr('check_time','>=',$since)->whereOr('update','>=',$since);if($recent)$q->whereOr('id','in',$recent);if($existing)$q->whereOr('id','in',$existing);})->select()->toArray();$this->prepareIssues($rows);
        foreach($rows as $r){
            $d=$this->issueData($r['id']);$receives=$aid>0 && in_array($aid,$notify,true);
            // 使用异常原始点检班次，避免班组换班后通知对象发生变化。
            $shift=(int)($d['record']['shift']??0);$field=$shift===1?'title':($shift===2?'content':null);
            foreach($projects[(int)($d['team']['project']??0)]??[] as $config)if($aid>0 && $field!==null && (int)$config[$field]===$aid)$receives=true;
            if(!$receives)continue;$allowed[]=(int)$r['id'];
            $p=$this->issuePermissions($account,$d);if(!$p['canView'])continue;$i=$this->presentIssue($account,$d);$fields=['设备'=>$i['deviceName'],'资产编号'=>$i['asset'],'异常'=>$i['description'],'上报人'=>$i['reporter'],'班组'=>$i['teamName'],'处理人'=>$i['ownerName']];$route='/pages/check-issue/detail?id='.$r['id'];$at=max((int)$r['check_time'],(int)$r['update'],(int)$d['flow']['updated_at']);
            if((int)$r['status']===1)$items[]=\app\mobile\service\MessageInbox::item('check-issue',$r['id'],'feedback','点检异常待处理','待处理',$fields,$route,$p['canFeedback']?'pending':'notice',$at);
            if((int)$r['status']===2)$items[]=\app\mobile\service\MessageInbox::item('check-issue',$r['id'],'confirm','点检异常待确认','待确认',$fields,$route,$p['canConfirm']?'pending':'notice',$at);
            $log=$this->latestLogs[$r['id']]??null;
            if( $log && (int)$log['created_at']>=$since && $log['action']!=='上报异常')$items[]=\app\mobile\service\MessageInbox::item('check-issue',$r['id'],'result-'.$log['id'],'点检异常'.$log['action'],$i['statusName'],$fields+['处理说明'=>$log['note']],$route,'notice',(int)$log['created_at']);
        }
        // 配置移除后同步收回旧通知，不再保留未授权人员的未读消息。
        $stale=Db::name('message')->where(['auth_id'=>$account['id'],'business'=>'check-issue'])->whereIn('state',['pending','notice']);
        if($allowed)$stale->whereNotIn('business_id',$allowed);
        $stale->update(['state'=>'closed','updated_at'=>$this->now()]);
        return $items;
    }
}
