<?php
/** 默认预览；--apply 保留数据改名或新增故障表、本人提醒订阅表及新版后台菜单，不改业务表。 */
function templateFailureSchema($prefix) {
    if (!preg_match('/^[a-zA-Z0-9_]*$/D',$prefix)) throw new RuntimeException('Invalid prefix');
    return ["CREATE TABLE IF NOT EXISTS `{$prefix}template_failure` (
        id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, open_key CHAR(64) NULL,
        template_key VARCHAR(64) NOT NULL, template_id VARCHAR(100) NOT NULL DEFAULT '',
        stage VARCHAR(32) NOT NULL, error_code INT NOT NULL DEFAULT 0,
        error_message TEXT NOT NULL, http_status INT NOT NULL DEFAULT 0, curl_errno INT NOT NULL DEFAULT 0,
        business_no VARCHAR(64) NOT NULL DEFAULT '', business_page VARCHAR(255) NOT NULL DEFAULT '',
        recipient_label VARCHAR(255) NOT NULL DEFAULT '', recipient_hash CHAR(64) NOT NULL DEFAULT '',
        occurrences INT UNSIGNED NOT NULL DEFAULT 1, first_at INT UNSIGNED NOT NULL, last_at INT UNSIGNED NOT NULL,
        status TINYINT NOT NULL DEFAULT 0, resolved_at INT UNSIGNED NOT NULL DEFAULT 0, resolved_by INT NOT NULL DEFAULT 0,
        resolution_note VARCHAR(500) NOT NULL DEFAULT '', last_alert_attempt_at INT UNSIGNED NOT NULL DEFAULT 0,
        last_alert_at INT UNSIGNED NOT NULL DEFAULT 0, alerted_occurrences INT UNSIGNED NOT NULL DEFAULT 0,
        alert_error VARCHAR(1000) NOT NULL DEFAULT '',
        PRIMARY KEY(id), UNIQUE KEY active_failure(open_key), KEY pending_list(status,last_at,id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='服务号发送异常，同类未处理异常合并计数'",
    "CREATE TABLE IF NOT EXISTS `{$prefix}template_alert_subscriber` (
        admin_id INT NOT NULL, enabled TINYINT NOT NULL DEFAULT 1, updated_at INT UNSIGNED NOT NULL,
        PRIMARY KEY(admin_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='后台账号自助订阅故障提醒'" ];
}
/** 先校验全部表名，再用一条RENAME原子改名，不覆盖并存表。 */
function templateFailureRenamePlan($prefix,$tables) {
    if (!preg_match('/^[a-zA-Z0-9_]*$/D',$prefix)) throw new RuntimeException('Invalid prefix');
    $renames=[];
    foreach (['template_failure','template_alert_subscriber'] as $name) {
        $old=$prefix.'wxoms_'.$name;$new=$prefix.$name;
        if (!in_array($old,$tables,true)) continue;
        if (in_array($new,$tables,true)) throw new RuntimeException('新旧表同时存在，已停止迁移以防覆盖数据：'.$old.' / '.$new);
        $renames[]='`'.$old.'` TO `'.$new.'`';
    }
    return $renames?['RENAME TABLE '.implode(', ',$renames)]:[];
}
function templateFailureMigrateTables($prefix,$apply=false) {
    if (!preg_match('/^[a-zA-Z0-9_]*$/D',$prefix)) throw new RuntimeException('Invalid prefix');
    $names=[];foreach (['template_failure','template_alert_subscriber'] as $name) { $names[]=$prefix.$name;$names[]=$prefix.'wxoms_'.$name; }
    $tables=\think\facade\Db::table('information_schema.TABLES')->where('TABLE_SCHEMA',\think\facade\Db::raw('DATABASE()'))->whereIn('TABLE_NAME',$names)->column('TABLE_NAME');
    $sql=array_merge(templateFailureRenamePlan($prefix,$tables),templateFailureSchema($prefix));
    if ($apply) foreach ($sql as $statement) \think\facade\Db::execute($statement);
    return $sql;
}
function templateFailureMenu() {
    $db='think\facade\Db';$key='system.template-failures';
    $row=$db::name('admin_menus')->where('menu_key',$key)->find();
    if (!$row) $db::name('admin_menus')->insert(['menu_key'=>$key,'parent_key'=>'system','title'=>'消息发送异常','icon'=>'Warning',
        'sort_order'=>30,'enabled'=>1,'updated_at'=>time()]);
    // 仅清理上次误加的这一个旧菜单及其角色引用，不动旧后台其他菜单。
    $oldIds=$db::name('admin_menus_vue')->whereIn('frontpath',['/user/templateFailures','user/templateFailures'])->column('id');
    if ($oldIds) {
        foreach ($db::name('admin_rights')->field('id,vue_right')->select() as $role) {
            $ids=array_values(array_filter(array_map('intval',explode(',',(string)$role['vue_right']))));
            $kept=array_values(array_diff($ids,array_map('intval',$oldIds)));
            if ($kept!==$ids) $db::name('admin_rights')->where('id',$role['id'])->update(['vue_right'=>implode(',',$kept)]);
        }
        $db::name('admin_menus_vue')->whereIn('id',$oldIds)->delete();
    }
    return ['menuKey'=>$key,'parentKey'=>'system','path'=>'/user/templateFailures','removedLegacyMenuIds'=>$oldIds];
}
if (PHP_SAPI!=='cli' || realpath($_SERVER['SCRIPT_FILENAME'] ?? '')!==__FILE__) return;
$root=$argv[1] ?? 'D:/phpstudy_pro/WWW/cqoms.com';if ($root==='--apply') $root='D:/phpstudy_pro/WWW/cqoms.com';
require $root.'/vendor/autoload.php';$app=new \think\App(rtrim($root,'/\\').'/');$app->initialize();
$connection=$app->config->get('database.connections.'.$app->config->get('database.default'));$apply=in_array('--apply',$argv,true);
$sql=templateFailureMigrateTables($connection['prefix'],$apply);$menu=null;
if ($apply) $menu=templateFailureMenu();
echo json_encode(['database'=>$connection['database'],'applied'=>$apply,'menu'=>$menu,'sql'=>$sql],JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT),PHP_EOL;
