<?php
namespace app\mobile\controller;

use think\facade\Db;
use think\facade\Filesystem;
use think\facade\Log;
use app\mobile\service\SuggestionTransfer;

class OmsSuggestion extends OmsBase
{
    public function messageItems($account,$since,\app\mobile\service\MessageInbox $inbox) {
        if(!$inbox->allowsSource($this))$this->fail('接口不存在',404);
        SuggestionTransfer::acceptExpired();
        $aid=$this->adminId($account);$departments=$this->departments($account);$employees=$this->leaderEmployees($account);$assign=$this->canAssign($account);$items=[];
        $rows=Db::name('onsite_suggestion_list')->where('status','>',0)->where(function($q)use($account,$aid,$departments,$employees,$assign,$since){
            $q->where(function($own)use($account,$since){$own->where('eid',$account['username'])->where(function($s)use($since){$s->where('status',3)->whereOr(function($r)use($since){$r->where('status',4)->where('update','>=',$since);});});});
            if($aid)$q->whereOr(function($owner)use($aid,$since){$owner->where('owner',$aid)->where(function($s)use($since){$s->whereIn('status',[2,3])->whereOr(function($r)use($since){$r->where('status',4)->where('update','>=',$since);});});});
            if($aid)$q->whereOr(function($receiver)use($aid){$receiver->where('transfer_to',$aid)->where('transfer_id','>',0);});
            if($assign)$q->whereOr('status',1);
            if($departments)$q->whereOr(function($r)use($departments){$r->where(['status'=>3,'selfshut'=>2])->whereIn('due_dpt',$departments);});
            if($employees)$q->whereOr(function($r)use($employees){$r->where(['status'=>3,'selfshut'=>1])->whereIn('eid',$employees);});
        })->select()->toArray();
        foreach($rows as $row){$p=$this->present($row,$account);$fields=['提报人'=>$p['ename'],'班组'=>$p['team'],'建议主题'=>$p['title'],'建议内容'=>$p['suggestion']];$route='/pages/suggestion/detail?id='.$row['id'];
            if($p['canReceiveTransfer'])$items[]=\app\mobile\service\MessageInbox::item('suggestion',$row['id'],'transfer-'.$row['transfer_id'],'合理化建议待接收','转移待确认',$fields+['原负责人'=>$p['ownerName'],'转移原因'=>$p['pendingTransfer']['reason']],$route,'pending',$p['pendingTransfer']['created_at']);
            if($p['canCancelTransfer'])$items[]=\app\mobile\service\MessageInbox::item('suggestion',$row['id'],'transfer-out-'.$row['transfer_id'],'合理化建议转移待确认','等待对方接收',$fields+['接收人'=>$p['pendingTransfer']['to_name'],'转移原因'=>$p['pendingTransfer']['reason']],$route,'pending',$p['pendingTransfer']['created_at']);
            foreach(['canAssign'=>['assign','合理化建议待分配'],'canFeedback'=>['feedback','合理化建议待反馈'],'canConfirm'=>['confirm','建议措施待完成确认']] as $right=>$task)if($p[$right])$items[]=\app\mobile\service\MessageInbox::item('suggestion',$row['id'],$task[0],$task[1],$p['statusName'],$fields,$route,'pending',($row['submit_time'] ?? 0) ?: ($row['update'] ?: ($row['create_date'] ?? 0)),$right==='canAssign'?0:($row['due_date']?((int)$row['due_date']+86399):0));
            if((int)$row['status']===4 && ((string)$row['eid']===(string)$account['username'] || $this->isOwner($account,$row)))$items[]=\app\mobile\service\MessageInbox::item('suggestion',$row['id'],'result','合理化建议'.$p['statusName'],$p['statusName'],$fields,$route,'notice',$row['update']);
        }
        if($aid)foreach(Db::name('onsite_suggestion_transfer')->where('state','<>','pending')->where('handled_at','>=',$since)->where(function($q)use($aid){$q->where('from_owner',$aid)->whereOr('to_owner',$aid);})->select()->toArray() as $transfer){
            $labels=['accepted'=>'已接收','rejected'=>'已拒绝','cancelled'=>'已撤回','assigned'=>'已分配'];
            // 通知不附带详情链接，历史接收人失去临时查看权限后仍能看到交接结果。
            $items[]=\app\mobile\service\MessageInbox::item('suggestion',$transfer['suggestion_id'],'transfer-result-'.$transfer['id'],'合理化建议转移'.($labels[$transfer['state']]??'已处理'),$labels[$transfer['state']]??'已处理',
                ['原负责人'=>$transfer['from_name'],'接收人'=>$transfer['to_name'],'转移原因'=>$transfer['reason'],'处理意见'=>$transfer['reply']],'/pages/suggestion/index?tab=feedback','notice',$transfer['handled_at']);
        }
        return $items;
    }
    private $leaderEmployeeNumbers = [];
    private function adminId($account) { return (int)$account['admin_id']; }
    private $configuredAssigners = null;
    private function configuredAssigners() {
        if ($this->configuredAssigners === null) {
            $rows = Db::name('onsite_base')->where('mid', 88)->column('content');
            $ids = count($rows) === 1 ? array_filter(array_unique(array_map('intval', explode(',', (string)$rows[0]))), function ($id) { return $id > 0; }) : [];
            $this->configuredAssigners = $ids ? Db::name('admin_user')->whereIn('id', $ids)->where('status', 1)->column('username', 'id') : [];
        }
        return $this->configuredAssigners;
    }
    private function canAssign($account) {
        $assigners = $this->configuredAssigners(); $id = $this->adminId($account);
        return isset($assigners[$id]) && (string)$assigners[$id] === (string)$account['username'];
    }
    private function departments($account) {
        $id = $this->adminId($account);
        return $id ? Db::name('member_base')->where(['mid'=>3, 'title'=>(string)$id])->column('mark') : [];
    }
    private function managedTeams($account) {
        $id = $this->adminId($account);
        if (!$id) return [];
        $key = $this->cacheKey('suggestion:managed-teams:' . $id);
        $teams = $this->cache()->get($key);
        if ($teams === null) {
            $teams = Db::name('team_list')->where('aid', $id)->column('id');
            $this->cache()->set($key, $teams, 300);
        }
        return $teams;
    }
    private function leaderEmployees($account) {
        $id = $this->adminId($account);
        if (!$id) return [];
        if (!array_key_exists($id, $this->leaderEmployeeNumbers)) {
            $teams = $this->managedTeams($account);
            $this->leaderEmployeeNumbers[$id] = $teams ? array_map('strval', Db::name('member_list')->alias('m')
                ->join('auth a', 'a.user_id=m.id AND a.username=m.eid')->whereIn('m.tid', $teams)->where('a.admin_id', 0)->column('m.eid')) : [];
        }
        return $this->leaderEmployeeNumbers[$id];
    }
    private function isConfirmer($account, $row) {
        if (!in_array((int)$row['selfshut'], [1, 2], true)) return false;
        if ((string)$row['eid'] === (string)$account['username']) return true;
        if ((int)$row['selfshut'] === 2) return in_array((string)$row['due_dpt'], array_map('strval', $this->departments($account)), true);
        return in_array((int)$row['status'], [3,4], true) && in_array((string)$row['eid'], $this->leaderEmployees($account), true);
    }
    private function canConfirm($account, $row) { return (int)$row['status'] === 3 && $this->isConfirmer($account, $row); }
    private function isOwner($account, $row) { return $this->adminId($account) > 0 && $this->adminId($account) === (int)$row['owner']; }
    private function result($data = null) { return json(['code'=>0, 'message'=>'成功', 'data'=>$data]); }
    private function integer($value, $label) {
        if (!is_scalar($value) || !preg_match('/^[1-9][0-9]{0,9}$/', (string)$value) || (float)$value > 2147483647) $this->fail($label . '不正确');
        return (int)$value;
    }
    private function row($account, $id, $lock = false) {
        $query = Db::name('onsite_suggestion_list')->where('id', $this->integer($id, '建议编号'))->where('status', '>', 0);
        if ($lock) $query = $query->lock(true);
        $row = $query->find();
        if (!$row) $this->fail('建议不存在或已删除', 404);
        if ((string)$row['eid'] !== (string)$account['username'] && !$this->isOwner($account, $row) && !$this->isTransferReceiver($account,$row) && !$this->canAssign($account) && !$this->isConfirmer($account, $row) && !$this->isResultLeader($account,$row)) $this->fail('无权查看或处理该建议', 403);
        return $row;
    }
    private function isResultLeader($account,$row) {
        if ((int)$row['status']!==4 || !$this->adminId($account)) return false;
        $member=Db::name('member_list')->where(['eid'=>(string)$row['eid'],'status'=>1])->find();
        return $member && (int)Db::name('team_list')->where(['id'=>$member['tid'],'status'=>1])->value('aid')===$this->adminId($account);
    }
    private function isTransferReceiver($account,$row) {
        return $this->adminId($account)>0 && !empty($row['transfer_id']) && (int)($row['transfer_to']??0)===$this->adminId($account);
    }
    private function isDepartmentWindow($account,$row) {
        return $this->isOwner($account,$row) && in_array((string)$row['due_dpt'],array_map('strval',$this->departments($account)),true);
    }
    private function present($row, $account) {
        $row['id'] = (int)$row['id']; $row['status'] = (int)$row['status']; $row['adopt'] = (int)$row['adopt']; $row['selfshut'] = (int)$row['selfshut'];
        $row['owner'] = (int)$row['owner'];
        $row['statusName'] = $row['adopt'] === 2 ? '未采纳' : ($row['status']===2 && $row['adopt']===1 ? '进行中' : ([1=>'待分配',2=>'待反馈',3=>'待确认',4=>'已完成'][$row['status']] ?? '未知状态'));
        $row['createdDate'] = date('Y-m-d', $row['creat_date']);
        $row['dueDate'] = $row['due_date'] ? date('Y-m-d', $row['due_date']) : '';
        $row['ownerName'] = $row['owner'] ? (Db::name('admin_user')->where('id', $row['owner'])->value('truename') ?: '未指定') : '未指定';
        $row['departmentName'] = $row['due_dpt'] ? (Db::name('admin_org')->where('id', $row['due_dpt'])->value('title') ?: '') : '';
        $row['reason'] = html_entity_decode((string)$row['reason'], ENT_QUOTES, 'UTF-8');
        $path = str_replace('\\', '/', (string)$row['img']);
        $row['imageUrl'] = strpos($path, '/storage/') === 0 ? 'https://www.cqoms.com' . $path : '';
        $row['canDelete'] = $row['status'] === 1 && (string)$row['eid'] === (string)$account['username'];
        $row['pendingTransfer'] = SuggestionTransfer::pending($row);
        $row['canFeedback'] = $row['status'] === 2 && $this->isOwner($account, $row) && !$row['pendingTransfer'];
        $row['canTransfer'] = $row['canFeedback'] && SuggestionTransfer::eligible($row);
        $row['canDirectAssign'] = $row['canTransfer'] && $this->isDepartmentWindow($account,$row);
        $row['canReceiveTransfer'] = $this->isTransferReceiver($account,$row) && (bool)$row['pendingTransfer'];
        $row['canCancelTransfer'] = $this->isOwner($account,$row) && (bool)$row['pendingTransfer'];
        $row['canAssign'] = $row['status'] === 1 && $this->canAssign($account);
        $row['canConfirm'] = $this->canConfirm($account, $row);
        return $row;
    }
    public function options() {
        return $this->guarded(function () {
            $this->requireMethod('GET'); $account = $this->current();
            $admin = $this->adminId($account) ? Db::name('admin_user')->find($this->adminId($account)) : null;
            $departments = $this->canAssign($account) ? Db::name('admin_org')->where('mid', 0)->field('id,title')->order('id')->select()->toArray() : [];
            $owners = $admin ? Db::name('admin_user')->where('status',1)->where('job','<>',79)->field('id,truename,dpt,username')->order('dpt,job,id')->select()->toArray() : [];
            $departmentNames = $admin ? Db::name('admin_org')->where('mid',0)->column('title','id') : [];
            $owners = array_values(array_filter($owners,function($owner)use($departmentNames){return isset($departmentNames[$owner['dpt']]);}));
            foreach($owners as &$owner){$owner['departmentName']=$departmentNames[$owner['dpt']];$owner['label']=$owner['truename'].' · '.$owner['departmentName'].'（'.$owner['username'].'）';}unset($owner);
            foreach ($departments as &$department) $department['id'] = (int)$department['id']; unset($department);
            foreach ($owners as &$owner) $owner['id'] = (int)$owner['id']; unset($owner);
            return $this->result(['requiresTeam'=>(int)$account['user_id'] > 0, 'departments'=>$departments, 'owners'=>$owners,
                'canFeedback'=>$this->adminId($account) > 0, 'canAssign'=>$this->canAssign($account), 'canConfirm'=>count($this->departments($account)) > 0 || count($this->managedTeams($account)) > 0]);
        });
    }
    public function records() {
        return $this->guarded(function () {
            $this->requireMethod('GET'); $account = $this->current();
            $page = $this->integer($this->request->get('page', 1), '页码');
            $scope = $this->request->get('scope', 'mine');
            SuggestionTransfer::acceptExpired();
            $query = Db::name('onsite_suggestion_list')->where('status', '>', 0);
            if ($scope === 'mine') $query->where('eid', $account['username']);
            elseif ($scope === 'feedback') {
                if (!$this->adminId($account)) $this->fail('仅后台人员可查看我的反馈', 403);
                $employees = $this->leaderEmployees($account);
                $query->where(function ($q) use ($account, $employees) {
                    $q->where('owner', $this->adminId($account));
                    $q->whereOr(function($receiver)use($account){$receiver->where('transfer_to',$this->adminId($account))->where('transfer_id','>',0);});
                    if ($employees) $q->whereOr(function ($confirmation) use ($employees) { $confirmation->where(['status'=>3, 'selfshut'=>1])->whereIn('eid', $employees); });
                    if ($this->canAssign($account)) $q->whereOr(function ($unassigned) {
                        $unassigned->where('status', 1)->where(function ($department) { $department->where('due_dpt', 0)->whereOr('due_dpt', 'null'); });
                    });
                });
            } elseif ($scope === 'confirm') {
                $departments = $this->departments($account); $employees = $this->leaderEmployees($account);
                $query->where('status', 3)->where(function ($q) use ($account, $departments, $employees) {
                    $q->whereOr(function ($q) use ($account) { $q->where('eid', $account['username'])->whereIn('selfshut', [1,2]); });
                    if ($departments) $q->whereOr(function ($q) use ($departments) { $q->where('selfshut', 2)->whereIn('due_dpt', $departments); });
                    if ($employees) $q->whereOr(function ($q) use ($employees) { $q->where('selfshut', 1)->whereIn('eid', $employees); });
                });
            } else $this->fail('列表类型不正确');
            $total = (clone $query)->count();
            $rows = $query->order('id desc')->limit(($page - 1) * 10, 10)->select()->toArray();
            return $this->result(['items'=>array_map(function ($row) use ($account) { return $this->present($row, $account); }, $rows), 'total'=>$total, 'page'=>$page]);
        });
    }
    public function scores() {
        return $this->guarded(function () {
            $this->requireMethod('GET'); $account = $this->current();
            $query = Db::name('onsite_suggestion_list')->where('eid', $account['username'])->where('status', '>', 0);
            $base = (clone $query)->count();
            $adopt = (clone $query)->where('adopt', 1)->count();
            $feedback = $this->adminId($account) ? Db::name('onsite_suggestion_list')->where('owner', $this->adminId($account))->where(['status'=>4, 'adopt'=>1])->count() : 0;
            $used = (int)Db::name('onsite_suggestion_score')->where('eid', $account['username'])->sum('used');
            return $this->result(['base'=>$base, 'adopt'=>$adopt, 'feedback'=>$feedback, 'used'=>$used, 'total'=>$base + $adopt + $feedback - $used]);
        });
    }
    public function detail() {
        return $this->guarded(function () { $this->requireMethod('GET'); $account = $this->current(); SuggestionTransfer::acceptExpired(); $row=$this->row($account, $this->request->get('id')); $data=$this->present($row,$account); $data['transferHistory']=SuggestionTransfer::history($row['id']); return $this->result($data); });
    }
    private function saveImage() {
        $file = $this->request->file('image');
        if (!$file) return null;
        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图片');
        $path = Filesystem::disk('public')->putFileAs('wx_upload/' . date('Ymd') . '/suggestion', $file, bin2hex(random_bytes(12)) . '.' . $types[$mime]);
        if (!$path) $this->fail('图片保存失败', 503);
        return '/storage/' . str_replace('\\', '/', $path);
    }
    public function create() {
        return $this->guarded(function () {
            $this->requireMethod('POST'); $account = $this->current();
        SuggestionTransfer::acceptExpired();
            $title = $this->requiredText('title', 4000); $suggestion = $this->requiredText('suggestion', 4000);
            if (mb_strlen($title) > 1000 || mb_strlen($suggestion) > 1000) $this->fail('问题描述和改善建议各不能超过1000字');
            if ((int)$account['user_id'] > 0) {
                $tid = $this->integer($this->request->post('teamId'), '班组');
                $team = Db::name('team_list')->where(['id'=>$tid, 'status'=>1])->find();
                if (!$team) $this->fail('班组已停用，请重新选择');
                $teamName = $team['team'];
            } else {
                $admin = Db::name('admin_user')->find($account['admin_id']);
                $department = Db::name('admin_org')->where('id', $admin['dpt'])->value('title') ?: '未设置部门';
                $position = Db::name('admin_org')->where('id', $admin['job'])->value('title') ?: '未设置职位';
                $teamName = $department . '-' . $position;
            }
            $selfshut = $this->integer($this->request->post('selfshut'), '确认方式');
            if (!in_array($selfshut, [1,2], true)) $this->fail('确认方式不正确');
            $person = Db::name((int)$account['user_type'] === 1 ? 'member_list' : 'admin_user')->find((int)$account['user_type'] === 1 ? $account['user_id'] : $account['admin_id']);
            $image = $this->saveImage();
            try {
                $id = Db::name('onsite_suggestion_list')->insertGetId(['eid'=>$account['username'], 'ename'=>$person[(int)$account['user_type'] === 1 ? 'ename' : 'truename'],
                    'dpt'=>(int)$account['user_type'] === 1 ? 1 : $person['dpt'], 'team'=>$teamName,
                    'phone'=>(int)$account['user_type'] === 1 ? Db::name('member_interview')->where('m_id', $account['user_id'])->value('phone') : $person['phone'],
                    'title'=>$title, 'suggestion'=>$suggestion, 'selfshut'=>$selfshut, 'img'=>$image, 'creat_date'=>time(), 'status'=>1, 'adopt'=>0]);
            } catch (\Throwable $error) {
                if ($image) Filesystem::disk('public')->delete(substr($image, strlen('/storage/')));
                throw $error;
            }
            $this->notify(['id'=>$id,'status'=>1], '新增建议，请分配责任人', []);
            return $this->result(['id'=>$id]);
        });
    }
    private function mutate($action) {
        $this->requireMethod('POST'); $account = $this->current();
        $row = SuggestionTransfer::locked(function () use ($account, $action) {
            $row = $this->row($account, $this->request->post('id'));
            $changes = $action($row, $account);
            SuggestionTransfer::updateSuggestion($row,$changes);
            return array_merge($row, $changes);
        });
        return [$row, $account];
    }
    public function remove() {
        return $this->guarded(function () {
            $this->mutate(function ($row, $account) {
                if ((int)$row['status'] !== 1 || (string)$row['eid'] !== (string)$account['username']) $this->fail('只能删除本人待分配的建议', 403);
                return ['status'=>0, 'update'=>time()];
            });
            return $this->result();
        });
    }
    public function assign() {
        return $this->guarded(function () {
            list($row, $account) = $this->mutate(function ($row, $account) {
                if (!$this->canAssign($account)) $this->fail('无权分配建议', 403);
                if ((int)$row['status'] !== 1) $this->fail('建议已分配，请刷新', 409);
                $action = $this->request->post('action', 'assign');
                if ($action === 'reject') {
                    $reason = $this->requiredText('reason', 4000);
                    if (mb_strlen($reason) > 1000) $this->fail('驳回原因不能超过1000字');
                    return ['adopt'=>2, 'status'=>4, 'reason'=>htmlspecialchars($reason, ENT_QUOTES, 'UTF-8'),
                        'due_dpt'=>0, 'owner'=>0, 'due_date'=>null, 'feedback_time'=>time(), 'submit_time'=>time(), 'update'=>time()];
                }
                if ($action !== 'assign') $this->fail('分配操作不正确');
                $dpt = $this->integer($this->request->post('departmentId'), '责任部门');
                if (!Db::name('admin_org')->where(['id'=>$dpt, 'mid'=>0])->find()) $this->fail('责任部门不存在');
                $owner = (int)Db::name('member_base')->where(['mid'=>3, 'mark'=>$dpt])->value('title');
                if (!$owner || !Db::name('admin_user')->where(['id'=>$owner, 'status'=>1])->find()) $this->fail('该部门尚未设置有效责任人');
                return ['due_dpt'=>$dpt, 'owner'=>$owner, 'status'=>2];
            });
            if ((int)$row['status'] === 2) $this->notify($row, '指定您为反馈责任人', []);
            else $this->notify($row, '反馈结果', []);
            return $this->result();
        });
    }
    public function transfer() {
        return $this->guarded(function () {
            list($row, $account) = $this->mutate(function ($row, $account) {
                if (!$this->isOwner($account, $row) || !SuggestionTransfer::eligible($row)) $this->fail('仅未反馈措施的当前负责人可以发起转移', 403);
                if (!empty($row['transfer_id'])) $this->fail('已有待确认的转移申请，请先撤回',409);
                $owner = $this->integer($this->request->post('ownerId'), '新责任人');
                $target = Db::name('admin_user')->where(['id'=>$owner,'status'=>1])->where('job','<>',79)->find();
                $department = $target ? Db::name('admin_org')->where(['id'=>$target['dpt'],'mid'=>0])->value('title') : null;
                if ($owner === $this->adminId($account) || !$target || !$department) $this->fail('请选择有有效部门的其他在用人员');
                $direct=$this->isDepartmentWindow($account,$row);
                $reason=$direct?'':$this->requiredText('reason',4000);if(mb_strlen($reason)>1000)$this->fail('转移原因不能超过1000字');
                $transferId=Db::name('onsite_suggestion_transfer')->insertGetId(['suggestion_id'=>$row['id'],'from_owner'=>$row['owner'],'to_owner'=>$owner,
                    'from_name'=>Db::name('admin_user')->where('id',$row['owner'])->value('truename')?:'未指定','to_name'=>$target['truename'],
                    'from_department'=>Db::name('admin_org')->where('id',$row['due_dpt'])->value('title')?:'未设置部门','to_department'=>$department,
                    'reason'=>$reason,'reply'=>$direct?'部门窗口直接分配，无需接收确认':'','state'=>$direct?'assigned':'pending','created_at'=>time(),
                    'actor_id'=>$direct?$this->adminId($account):0,'handled_at'=>$direct?time():0]);
                if($direct)return ['owner'=>$owner,'due_dpt'=>$target['dpt'],'transfer_id'=>0,'transfer_to'=>0,'update'=>time()];
                return ['transfer_id'=>$transferId,'transfer_to'=>$owner];
            });
            $this->notify($row, !empty($row['transfer_to'])?'合理化建议待接收':'部门窗口指定您为反馈责任人', [!empty($row['transfer_to'])?$row['transfer_to']:$row['owner']]);
            return $this->result();
        });
    }
    public function respondTransfer() {
        return $this->guarded(function(){
            $action=$this->request->post('action');
            if(!in_array($action,['accept','reject','cancel'],true))$this->fail('转移操作不正确');
            $transfer=null;
            list($row,$account)=$this->mutate(function($row,$account)use($action,&$transfer){
                $transferId=$this->integer($this->request->post('transferId'),'转移申请编号');
                $transfer=SuggestionTransfer::pending($row);
                if(!$transfer || (int)$transfer['id']!==$transferId)$this->fail('转移申请已处理或已撤回，请刷新',409);
                if($action==='cancel'){
                    if(!$this->isOwner($account,$row))$this->fail('仅当前负责人可以撤回转移',403);
                    $state='cancelled';$reply='发起人撤回';
                }else{
                    if(!$this->isTransferReceiver($account,$row))$this->fail('仅指定接收人可以处理',403);
                    $state=$action==='accept'?'accepted':'rejected';$reply='';
                    if($action==='reject'){$reply=$this->requiredText('reason',4000);if(mb_strlen($reply)>1000)$this->fail('拒绝原因不能超过1000字');}
                }
                $changes=['transfer_id'=>0,'transfer_to'=>0];$log=['state'=>$state,'reply'=>$reply,'actor_id'=>$this->adminId($account),'handled_at'=>time()];
                if($action==='accept'){
                    if(!SuggestionTransfer::eligible($row)||(int)$row['owner']!==(int)$transfer['from_owner'])$this->fail('建议已反馈措施或负责人已变化，不能接收',409);
                    $target=Db::name('admin_user')->where(['id'=>$account['admin_id'],'status'=>1])->where('job','<>',79)->find();
                    $department=$target?Db::name('admin_org')->where(['id'=>$target['dpt'],'mid'=>0])->value('title'):null;
                    if(!$department)$this->fail('接收人的账号或所属部门已失效');
                    $changes+=['owner'=>$target['id'],'due_dpt'=>$target['dpt'],'update'=>time()];
                    $log+=['to_name'=>$target['truename'],'to_department'=>$department];
                }
                Db::name('onsite_suggestion_transfer')->where('id',$transferId)->update($log);
                return $changes;
            });
            $titles=['accept'=>'合理化建议转移已接收','reject'=>'合理化建议转移已拒绝','cancel'=>'合理化建议转移已撤回'];
            $this->notify($row,$titles[$action],[$action==='cancel'?$transfer['to_owner']:$transfer['from_owner']]);
            return $this->result();
        });
    }
    public function feedback() {
        return $this->guarded(function () {
            list($row, $account) = $this->mutate(function ($row, $account) {
                if (!$this->isOwner($account, $row)) $this->fail('只有责任人可以反馈', 403);
                if ((int)$row['status'] !== 2) $this->fail('建议状态已变化，请刷新', 409);
                if (!empty($row['transfer_id'])) $this->fail('请先撤回待确认的转移申请，再填写反馈',409);
                $adopt = $this->integer($this->request->post('adopt'), '采纳选项');
                if (!in_array($adopt, [1,2], true)) $this->fail('采纳选项不正确');
                $reason = htmlspecialchars($this->requiredText('reason', 4000), ENT_QUOTES, 'UTF-8');
                if (mb_strlen($reason) > 1000) $this->fail('反馈内容过长，请缩短后重试');
                $mode = $this->request->post('mode'); if (!in_array($mode, ['save','submit'], true)) $this->fail('提交方式不正确');
                $date = null;
                if ($adopt === 1) {
                    $text = $this->requiredText('dueDate', 10); $parsed = \DateTime::createFromFormat('!Y-m-d', $text);
                    if (!$parsed || $parsed->format('Y-m-d') !== $text || $parsed->getTimestamp() < strtotime('today -3 days')) $this->fail('请选择有效完成日期（最早为三天前）');
                    $date = $parsed->getTimestamp();
                }
                $status = $adopt === 2 ? 4 : ($mode === 'submit' ? ((int)$row['selfshut'] === 2 ? 4 : 3) : 2);
                $changes = ['adopt'=>$adopt, 'reason'=>$reason, 'due_date'=>$date, 'status'=>$status, 'feedback_time'=>time()];
                if ($status >= 3) $changes['submit_time'] = time();
                if ($status === 4) $changes['update'] = time();
                return $changes;
            });
            if ((int)$row['status'] === 3) $this->notify($row, '请确认改善措施是否完成', []);
            elseif ((int)$row['status'] === 4) $this->notify($row, '反馈结果', []);
            return $this->result();
        });
    }
    public function confirm() {
        return $this->guarded(function () {
            list($row, $account) = $this->mutate(function ($row, $account) {
                if (!$this->canConfirm($account, $row)) $this->fail('当前建议不能由您确认', 403);
                return ['status'=>4, 'update'=>time()];
            });
            $this->notify($row, '改善措施已确认完成', []);
            return $this->result();
        });
    }
    protected function notify($row, $title, $recipients) {
        try {
            $service=$this->templateService();$page='pages/suggestion/detail?id='.$row['id'];
            if(strpos($title,'合理化建议转移已')===0)$page='pages/suggestion/index?tab=feedback';
            if($title==='合理化建议待接收'){
                $transfer=SuggestionTransfer::pending($row);
                if(!$transfer)return true; // 已撤回或已处理，不再发送过时的接收待办。
                return $service->send('workflow_pending',$service->admins([$transfer['to_owner']]),[
                    'name'=>'建议#'.$row['id'].'转移确认','initiator'=>$transfer['from_name'],
                    'time'=>$service::time($transfer['created_at']),'reason'=>$transfer['reason'],'step'=>'请在24小时内确认接收或拒绝，超时未拒绝将自动同意',
                ],$page);
            }
            if ($title==='反馈结果') {
                $recipients=array_merge($service->employees([$row['eid']]),$service->employeeLeaders($row['eid']));
                return $service->send('feedback_result',$recipients,[
                    'type'=>(int)$row['adopt']===2?'合理化建议·不采纳':'合理化建议·采纳完成','content'=>$row['title'],
                    'owner'=>$row['owner']?$service->adminName($row['owner']):$service->adminName($this->current()['admin_id']),
                    'reply'=>$row['reason'],'time'=>$service::time($row['update']),
                ],$page);
            }
            if ($title==='请确认改善措施是否完成') {
                $recipients=$service->employees([$row['eid']]);
                if ((int)$row['selfshut']===1) $recipients=array_merge($recipients,$service->employeeLeaders($row['eid']));
                else $recipients=array_merge($recipients,$service->admins(Db::name('member_base')->where(['mid'=>3,'mark'=>$row['due_dpt']])->column('title')));
                return $service->send('workflow_pending',$recipients,[
                    'name'=>'合理化建议完成确认','initiator'=>$service->adminName($row['owner']),'time'=>$service::time($row['submit_time']),
                    'reason'=>$row['reason'],'step'=>'确认改善措施完成',
                ],$page);
            }
            if ($title==='改善措施已确认完成') return $service->send('workflow_approved',$service->admins([$row['owner']]),[
                'name'=>'合理化建议完成确认','approver'=>$this->profileData($this->current())['name'],'number'=>(string)$row['id'],'time'=>$service::time($row['update']),
            ],$page);
            $recipients=$service->admins($recipients ?: ((int)$row['status']===1?array_keys($this->configuredAssigners()):[$row['owner']]));
            $assigned=in_array($title,['指定您为反馈责任人','部门窗口指定您为反馈责任人'],true);
            return $service->send('work_order_pending',$recipients,[
                'notice'=>$assigned?'分配给你，请及时反馈':$title,'number'=>(string)$row['id'],'time'=>$service::time(time()),'name'=>$assigned?'合理化建议·待反馈':'合理化建议',
            ],$page);
        } catch (\Throwable $error) { Log::warning('oms suggestion notification unavailable: '.$error->getMessage()); return false; }
    }
}
