<?php
namespace app\mobile\service;

use think\facade\Db;

/** 原建议表保留 MyISAM；短时表锁串行化业务写入，新增记录表使用 InnoDB。 */
class SuggestionTransfer {
    private static $undo = null;
    public static function locked($action) {
        $config=config('database.connections.'.config('database.default'));$prefix=$config['prefix'];
        if(!preg_match('/^[a-zA-Z0-9_]*$/D',$prefix))throw new \RuntimeException('Invalid prefix');
        Db::query('SELECT 1');
        $pdo=Db::connect()->getConnection()->getPdo();$locked=false;self::$undo=null;
        // 不调用 START TRANSACTION：MySQL 会因此释放 LOCK TABLES。
        $pdo->exec('SET autocommit=0');
        try {
            $tables=['onsite_suggestion_list'=>'WRITE','onsite_suggestion_transfer'=>'WRITE','admin_user'=>'READ','admin_org'=>'READ',
                'onsite_base'=>'READ','member_base'=>'READ','member_list'=>'READ','team_list'=>'READ','auth'=>'READ'];
            $locks=[];foreach($tables as $table=>$mode)$locks[]='`'.$prefix.$table.'` '.$mode;
            $locks[]='`'.$prefix.'member_list` AS `m` READ';$locks[]='`'.$prefix.'auth` AS `a` READ';
            $pdo->exec('LOCK TABLES '.implode(', ',$locks));$locked=true;
            $result=$action();$pdo->exec('COMMIT');self::$undo=null;
            return $result;
        } catch(\Throwable $error) {
            // MyISAM 不支持回滚，在仍持有表锁时恢复本次修改的原值。
            try { if(self::$undo)Db::name('onsite_suggestion_list')->where('id',self::$undo['id'])->update(self::$undo['fields']); }
            finally { $pdo->exec('ROLLBACK'); }
            throw $error;
        } finally {
            self::$undo=null;
            try { if($locked)$pdo->exec('UNLOCK TABLES'); }
            finally { $pdo->exec('SET autocommit=1'); }
        }
    }
    /** 每条独立持锁提交，兼容原建议表 MyISAM 的失败补偿。 */
    public static function acceptExpired() {
        $now=time();$count=0;
        $ids=Db::name('onsite_suggestion_transfer')->where('state','pending')->where('created_at','<=',$now-86400)->column('id');
        foreach($ids as $id)$count+=self::locked(function()use($id,$now){
            $transfer=Db::name('onsite_suggestion_transfer')->where(['id'=>$id,'state'=>'pending'])->find();
            if(!$transfer || (int)$transfer['created_at']>$now-86400)return 0;
            $row=Db::name('onsite_suggestion_list')->where('id',$transfer['suggestion_id'])->find();
            if(!$row || (int)$row['transfer_id']!==(int)$id)return 0;
            $target=Db::name('admin_user')->where(['id'=>$transfer['to_owner'],'status'=>1])->where('job','<>',79)->find();
            $department=$target?Db::name('admin_org')->where(['id'=>$target['dpt'],'mid'=>0])->value('title'):null;
            $valid=self::eligible($row) && (int)$row['owner']===(int)$transfer['from_owner'] && $department;
            $changes=['transfer_id'=>0,'transfer_to'=>0];
            $log=['state'=>'cancelled','reply'=>'超时处理时建议状态或接收人已失效，自动撤销转移','actor_id'=>0,'handled_at'=>$now];
            if($valid){
                $changes+=['owner'=>$target['id'],'due_dpt'=>$target['dpt'],'update'=>$now];
                $log=array_merge($log,['state'=>'accepted','reply'=>'24小时内未拒绝，系统自动同意接收','to_name'=>$target['truename'],'to_department'=>$department]);
            }
            self::updateSuggestion($row,$changes);
            Db::name('onsite_suggestion_transfer')->where('id',$id)->update($log);
            return 1;
        });
        return $count;
    }
    public static function updateSuggestion($row,$changes) {
        self::$undo=['id'=>$row['id'],'fields'=>array_intersect_key($row,$changes)];
        Db::name('onsite_suggestion_list')->where('id',$row['id'])->update($changes);
    }
    public static function eligible($row) {
        return (int)$row['status'] === 2 && (int)$row['adopt'] === 0
            && trim((string)($row['reason'] ?? '')) === '' && !(int)($row['feedback_time'] ?? 0);
    }
    public static function pending($row) {
        if (empty($row['transfer_id'])) return null;
        $item=Db::name('onsite_suggestion_transfer')->where(['id'=>$row['transfer_id'],'suggestion_id'=>$row['id'],'state'=>'pending'])->find();
        return $item ? self::present($item) : null;
    }
    public static function history($id) {
        $rows = Db::name('onsite_suggestion_transfer')->where('suggestion_id',$id)->order('id desc')->select()->toArray();
        return array_map([self::class,'present'],$rows);
    }
    public static function present($row) {
        foreach (['id','suggestion_id','from_owner','to_owner','actor_id','created_at','handled_at'] as $field) $row[$field] = (int)$row[$field];
        $row['createdAt'] = date('Y-m-d H:i', $row['created_at']);
        $row['handledAt'] = $row['handled_at'] ? date('Y-m-d H:i', $row['handled_at']) : '';
        return $row;
    }
    public static function cancel($row, $actor, $reason) {
        if (empty($row['transfer_id'])) return;
        Db::name('onsite_suggestion_transfer')->where(['id'=>$row['transfer_id'],'suggestion_id'=>$row['id'],'state'=>'pending'])
            ->update(['state'=>'cancelled','reply'=>$reason,'actor_id'=>$actor,'handled_at'=>time()]);
    }
}
