/**
 * @file manager.js —— Phase 0 重构后承担"剩余的编排层"。
 *
 * 大部分功能已迁出：
 *   - 状态：infra/store.js (currentTablesState / highlights / updatedTables)
 *   - 持久化：infra/persistence.js (saveStateToMessage / commitToLastMessage)
 *   - 推演：actions/applyOperations.js (executor.js 改造为 legacy formatter)
 *   - UI 突变：actions/ui-mutations.js (addRow / addColumn / ... / clearAllTables，Phase 0.4)
 *   - SuperMemory 分发：events-dispatch.js (dispatchTableUpdate / dispatchAllTablesUpdate)
 *   - 渲染：rendering.js (3 个 toCsv)
 *   - 模板：templates.js
 *   - 预设：preset.js
 *
 * 本文件保留：
 *   - 默认表格模板 + getDefaultTables
 *   - triggerSync（SuperMemory 全量同步入口）
 *   - loadTables 的多档回退逻辑
 *   - updateTableFromText / updateTableFromOps 编排
 *   - rollbackState / rollbackAndRefill
 *
 * 所有原先 export 的接口一律保留兼容（移走的统一 re-export），调用方零改动。
 *
 * @typedef {import('./dto/Table.js').TableState} TableState
 */

import { getContext, extension_settings } from '/scripts/extensions.js';
import { saveChat } from '/script.js';
import { saveChatDebounced } from '../../utils/utils.js';
import { extensionName } from '../../utils/settings.js';

import { log } from './logger.js';
import { executeCommands } from './executor.js';
import { applyOperations } from './actions/applyOperations.js';
import { fillWithSecondaryApi } from './secondary-filler.js';
import { renderTables } from '../../ui/table-bindings.js';
import { updateOrInsertTableInChat } from '../../ui/message-table-renderer.js';
import { dispatchTableUpdate, dispatchAllTablesUpdate } from './events-dispatch.js';

// ── UI 突变（Phase 0.4 迁至 actions/ui-mutations.js，此处 re-export 保持兼容） ──
import { commitPendingDeletions } from './actions/ui-mutations.js';
export {
    deleteColumn,
    moveRow,
    insertRow,
    addRow,
    addColumn,
    updateHeader,
    deleteRow,
    restoreRow,
    commitPendingDeletions,
    insertColumn,
    moveColumn,
    deleteTable,
    addTable,
    renameTable,
    moveTable,
    updateTableRules,
    updateRow,
    clearAllTables,
    updateColumnWidth,
} from './actions/ui-mutations.js';

// ── 新模块（IAD 拆分后的依赖） ────────────────────────────────────────────
import {
    getState,
    setState,
    addHighlight as _storeAddHighlight,
    getHighlights as _storeGetHighlights,
    clearHighlights as _storeClearHighlights,
    markTableUpdated,
    getUpdatedTables as _storeGetUpdatedTables,
    clearUpdatedTables as _storeClearUpdatedTables,
} from './infra/store.js';

import {
    saveStateToMessage as _persistSaveStateToMessage,
    commitToLastMessage,
    TABLE_DATA_KEY,
} from './infra/persistence.js';

import {
    tablesToCsv,
    tablesToCsvWithSelection,
    tablesToCsvContentOnly,
} from './rendering.js';

import {
    getBatchFillerRuleTemplate as _tplGetBatchFillerRuleTemplate,
    saveBatchFillerRuleTemplate as _tplSaveBatchFillerRuleTemplate,
    getBatchFillerFlowTemplate as _tplGetBatchFillerFlowTemplate,
    saveBatchFillerFlowTemplate as _tplSaveBatchFillerFlowTemplate,
    getAiFlowTemplateForInjection as _tplGetAiFlowTemplateForInjection,
    saveAiTemplate as _tplSaveAiTemplate,
    getAiTemplate as _tplGetAiTemplate,
} from './templates.js';

import {
    exportPreset as _presetExportPreset,
    exportPresetFull as _presetExportPresetFull,
    importPreset as _presetImportPreset,
    clearGlobalPreset as _presetClearGlobalPreset,
    importGlobalPreset as _presetImportGlobalPreset,
} from './preset.js';

// ── SuperMemory 同步入口 ──────────────────────────────────────────────────

/**
 * 主动触发所有表格同步到 SuperMemory（外部调用入口）。
 */
export function triggerSync() {
    dispatchAllTablesUpdate();
}

// ── 状态访问（store 包装层） ──────────────────────────────────────────────

export function addHighlight(tableIndex, rowIndex, colIndex) {
    _storeAddHighlight(tableIndex, rowIndex, colIndex);
}

export function getHighlights() {
    return _storeGetHighlights();
}

export function clearHighlights() {
    _storeClearHighlights();
}

export function getUpdatedTables() {
    return _storeGetUpdatedTables();
}

export function clearUpdatedTables() {
    _storeClearUpdatedTables();
}

export function setMemoryState(newState) {
    setState(newState);
}

export function getMemoryState() {
    return getState();
}

export function loadMemoryState(state) {
    if (!state) return;
    setState(state);
    renderTables();
    updateOrInsertTableInChat();
    log('[SuperMemory] 已从元数据恢复内存状态并刷新 UI。', 'info');
}

export function saveMemoryState() {
    const context = getContext();
    if (context.chat && context.chat.length > 0) {
        const lastMessage = context.chat[context.chat.length - 1];
        if (_persistSaveStateToMessage(getState(), lastMessage)) {
            // 不在此处强制 saveChat，避免高频；调用方决定时机
            return true;
        }
    }
    return false;
}

export function saveStateToMessage(stateToSave, targetMessage) {
    return _persistSaveStateToMessage(stateToSave, targetMessage);
}

// ── 默认模板 ──────────────────────────────────────────────────────────────

const defaultTemplate = {
    "tables": [
        {
          "name": "时空栏",
          "headers": ["日期", "时段", "时间", "地点", "此地角色"],
          "note": "【核心作用】此表格用于精确追踪故事发生的即时时空背景，确保时间与空间的连续性。它应该始终只包含一行，代表当前的“镜头”位置。\n【字段详解】\n- 日期: 格式为'YYYY-MM-DD'。若日期未知，请根据上下文合理推断或设定一个初始日期，如'大夏3年-9月-10日'。\n- 时段: 严格遵循规定（凌晨：0-5时；早晨：5-8时；上午：8-11时；中午：11-13时；下午：13-16时；傍晚：16-19时；晚上：19-24时）。\n- 时间: 格式为'HH:MM'。若时间未知，可根据时段估算，如'08:30'。\n- 地点: 描述当前场景发生的具体位置，应尽可能精确，例如'XX街的咖啡馆'而非'城里'。\n- 此地角色: 列出当前场景中所有在场且参与互动的主要角色，用'/'分隔。",
          "rule_add": "【触发条件】当故事开始，且此表格为空时，必须立即根据初始场景创建第一行。",
          "rule_delete": "【触发条件】任何时候，如果此表格的行数超过一行，必须删除旧的行，只保留最新、最准确的一行。",
          "rule_update": "【触发条件】当以下任一情况发生时，必须更新此行：\n1. 时间发生显著跳跃（例如，'几小时后'、'第二天'）。\n2. 角色从一个地点移动到另一个地点。\n3. 场景中关键角色的出入导致在场人员发生变化。",
          "charLimitRules": {},
          "rowLimitRule": 1,
          "rows": []
        },
        {
          "name": "角色栏",
          "headers": ["角色名", "外貌", "身形", "衣着", "性格", "身份", "职业", "与<user>关系", "爱好", "住所", "其他重要信息"],
          "note": "【核心作用】此表格是角色关系和状态的核心数据库，用于记录所有在故事中出现的重要角色的详细信息。\n【字段详解】\n- 角色名: 角色的唯一标识。\n- 外貌: 描述五官、发型、发色、肤色等面部特征。\n- 身形: 描述身高、体型、肌肉状况、特殊身体标记（如伤疤）等。\n- 衣着: 描述角色当前或标志性的穿着，包括服装、配饰等。\n- 性格: 概括角色的核心性格特质，使用1-3个关键词，如'勇敢/鲁莽/忠诚'。\n- 身份: 角色的社会背景或出身，如'贵族后裔'、'流浪者'。\n- 职业: 角色赖以谋生的工作或职责，如'佣兵'、'学者'。\n- 与<user>关系: 描述该角色与主角<user>之间的社会或情感关系，如'盟友'、'导师'、'敌人'。\n- 爱好: 角色的兴趣和消遣活动。\n- 住所: 角色的常住地。\n- 其他重要信息: 记录任何不属于以上类别但对角色至关重要的信息，如特殊能力、过去的经历等。",
          "rule_add": "【触发条件】当一个有名有姓的角色首次出现，并与<user>或当前剧情发生有意义的互动时，必须为其创建新的一行。",
          "rule_delete": "【触发条件】当一个角色被确认永久性死亡（非假死或失踪），且其存在不再对后续剧情有直接影响时，可以删除该行。",
          "rule_update": "【触发条件】当角色的任何信息发生持久性或关键性变化时，必须更新对应单元格。例如：\n1. 外貌/身形/衣着发生永久性改变（如断肢、换上新装备）。\n2. 性格因重大事件而扭转。\n3. 身份或职业发生变更（如继承王位、被解雇）。\n4. 与<user>的关系发生根本性转变（如从敌人变为盟友）。",
          "charLimitRules": { "10": 30 },
          "rowLimitRule": 0,
          "rows": []
        },
        {
            "name": "关系栏",
            "headers": ["主动方", "被动方", "关系", "详情"],
            "columnWidths": [],
            "note": "【核心作用】专门用于记录除主角<user>以外的角色之间的复杂人际关系网（NPC to NPC）。\n【字段详解】\n- 主动方: 关系的发起者或主体（例如'艾克'）。\n- 被动方: 关系的接收者或对象（例如'莉娜'）。\n- 关系: 用简短的词汇描述两者之间的关系本质，如'暗恋'、'世仇'、'师徒'。\n- 详情: 对这段关系的具体描述或背景补充。",
            "rule_add": "【触发条件】当两个NPC之间展现出明确的、非临时性的人际关系时，应添加新行。",
            "rule_delete": "【触发条件】当两个NPC之间的关系彻底断绝且不再影响剧情，或者其中一方彻底消失/死亡时，可以删除。",
            "rule_update": "【触发条件】当两个NPC之间的关系性质发生转变（如从'盟友'变为'背叛者'）时，必须更新。",
            "charLimitRules": {},
            "rowLimitRule": 0,
            "rows": [],
            "rowStatuses": []
        },
        {
          "name": "任务栏",
          "headers": ["任务名", "类型", "详情", "状态", "执行者", "地点", "开始时间/结束时间", "结果"],
          "note": "【核心作用】追踪故事中的主要情节线、目标和挑战。只记录对剧情发展有重大影响的“任务”，忽略日常琐事。\n【字段详解】\n- 任务名: 任务的简洁概括，如'寻找失落的神器'。\n- 类型: 任务的分类，如'主线'、'支线'、'个人'、'约定'。\n- 详情: 对任务目标和背景的简要描述。\n- 状态: 任务的当前进展，如'未开始'、'进行中'、'已完成'、'已失败'、'已取消'。\n- 执行者: 负责完成此任务的角色名。\n- 地点: 任务关键环节发生的地点。\n- 开始时间/结束时间: 记录任务的起止时间，格式'YYYY-MM-DD'，若未结束则结束时间留空。\n- 结果: 任务完成或失败后的最终结果。",
          "rule_add": "【触发条件】当以下情况发生时，应添加新行：\n1. 角色接下一个明确的、有目标的委托或命令。\n2. 角色们达成一个具体的、需要在未来执行的约定。\n3. 角色为自己设定一个长期的、关键性的目标。",
          "rule_delete": "【触发条件】当任务列表超过10行时，优先删除最早的、已经“已完成”且与当前剧情关联度最低的任务。如果存在内容完全重复的任务，应删除。",
          "rule_update": "【触发条件】当任务的“状态”发生任何变化时，必须更新。例如，从'进行中'变为'已完成'。当任务的“详情”或“结果”有新的关键信息补充时，也应更新。",
          "charLimitRules": {},
          "rowLimitRule": 10,
          "rows": []
        },
        {
          "name": "物品栏",
          "headers": ["物品名", "类型", "详情", "状态", "拥有者", "重要原因"],
          "note": "【核心作用】记录那些在故事中具有特殊功能、背景或情感价值的关键物品。普通物品不应记录。\n【字段详解】\n- 物品名: 物品的名称。\n- 类型: 物品的分类，如'武器'、'道具'、'信物'、'关键物品'。\n- 详情: 描述物品的外观、材质和已知功能。\n- 状态: 物品的当前状况，如'完好'、'破损'、'能量耗尽'。\n- 拥有者: 当前持有该物品的角色名。\n- 重要原因: 解释该物品为何重要，例如'是解开谜题的钥匙'或'是母亲的遗物'。",
          "rule_add": "【触发条件】当一个物品被明确赋予了特殊意义（如被赠予、在关键事件中扮演重要角色）或展示出独特功能时，应为其创建条目。",
          "rule_delete": "【触发条件】当一个物品被彻底摧毁、消耗完毕或永久失去其特殊意义时，可以删除。",
          "rule_update": "【触发条件】当物品的“状态”（如被损坏）、“拥有者”（如被转交或被盗）或“详情”（如发现了新功能）发生变化时，必须更新。",
          "charLimitRules": {},
          "rowLimitRule": 0,
          "rows": []
        },
        {
          "name": "技能栏",
          "headers": ["技能名", "技能效果"],
          "note": "【核心作用】专门用于记录主角<user>掌握的各种技能、魔法、被动能力或特殊专长。\n【字段详解】\n- 技能名: 技能的正式名称。\n- 技能效果: 清晰、简洁地描述该技能使用时产生的具体效果、消耗和限制条件。",
          "rule_add": "【触发条件】当<user>在故事中首次成功施展或习得一个全新的、表格中未记录的技能时，必须添加。",
          "rule_delete": "【触发条件】如果发现表格中存在两个描述完全相同的重复技能，应删除其中一个。如果记录了非<user>的技能，应立即删除。",
          "rule_update": "【触发条件】当一个已知技能的效果发生进化、变异或被添加了新的限制/效果时（例如，技能升级），必须更新其“技能效果”描述。",
          "charLimitRules": {},
          "rowLimitRule": 0,
          "rows": []
        },
        {
          "name": "设定栏",
          "headers": ["类型", "具体描述"],
          "note": "【核心作用】此表格记录了来自<user>的、超越故事本身的“元指令”或世界观设定，拥有最高解释权。内容应被严格遵守，禁止AI自行修改。\n【字段详解】\n- 类型: 指令的分类，如'世界观设定'、'剧情走向要求'、'角色行为禁令'。\n- 具体描述: 完整、准确地记录<user>提出的具体要求。",
          "rule_add": "【触发条件】当<user>通过括号、旁白或其他明确的“第四面墙”方式，提出关于故事背景、规则或未来走向的指令时，必须记录于此。",
          "rule_delete": "【触发条件】只能在<user>明确表示要移除或废弃某条设定时，才能删除对应行。",
          "rule_update": "【触发条件】只能在<user>明确表示要修改某条设定时，才能更新对应行的描述。",
          "charLimitRules": {},
          "rowLimitRule": 0,
          "rows": []
        }
    ]
};

function getDefaultTables() {
    log('从预设模板生成默认表格...', 'info');
    const tables = JSON.parse(JSON.stringify(defaultTemplate.tables));
    tables.forEach(table => {
        table.charLimitRule = { columnIndex: -1, limit: 0 };
        table.rowLimitRule = 0;
        table.columnWidths = [];
    });
    return tables;
}

// ── 加载 ──────────────────────────────────────────────────────────────────

export function loadTables(stopIndex = -1) {
    const context = getContext();

    // 1. 优先从聊天记录中找已存的状态
    if (context && context.chat && context.chat.length > 0) {
        const startIndex = (stopIndex === -1 ? context.chat.length - 1 : stopIndex - 1);
        for (let i = startIndex; i >= 0; i--) {
            const message = context.chat[i];
            if (message.extra && message.extra[TABLE_DATA_KEY]) {
                log(`在第 ${i} 条消息中找到基准表格数据。`, 'info');
                let loadedState = JSON.parse(JSON.stringify(message.extra[TABLE_DATA_KEY]));

                loadedState.forEach(table => {
                    if (table.note === undefined) table.note = '无';
                    if (table.rule_add === undefined) table.rule_add = '允许';
                    if (table.rule_delete === undefined) table.rule_delete = '允许';
                    if (table.rule_update === undefined) table.rule_update = '允许';

                    // 多列规则兼容
                    if (table.charLimitRule && !table.charLimitRules) {
                        table.charLimitRules = {};
                        if (table.charLimitRule.columnIndex !== -1 && table.charLimitRule.limit > 0) {
                            table.charLimitRules[table.charLimitRule.columnIndex] = table.charLimitRule.limit;
                        }
                    }
                    delete table.charLimitRule;

                    if (table.rowLimitRule === undefined) table.rowLimitRule = 0;
                    if (table.columnWidths === undefined) table.columnWidths = [];

                    if (!table.rowStatuses) {
                        table.rowStatuses = Array(table.rows.length).fill('normal');
                    }
                });

                setState(loadedState);
                dispatchAllTablesUpdate();
                return getState();
            }
        }
    }

    // 2. 全局预设
    if (extension_settings[extensionName]?.global_table_preset) {
        log('未在聊天记录中找到表格，正在加载全局预设...', 'info');
        try {
            const globalPreset = extension_settings[extensionName].global_table_preset;
            setState(JSON.parse(JSON.stringify(globalPreset.tables)));

            if (globalPreset.batchFillerRuleTemplate !== undefined) {
                _tplSaveBatchFillerRuleTemplate(globalPreset.batchFillerRuleTemplate);
            }
            if (globalPreset.batchFillerFlowTemplate !== undefined) {
                _tplSaveBatchFillerFlowTemplate(globalPreset.batchFillerFlowTemplate);
            }

            dispatchAllTablesUpdate();
            return getState();
        } catch (error) {
            log(`加载全局预设失败: ${error.message}`, 'error');
        }
    }

    // 3. 默认模板
    log('未找到任何表格数据或全局预设，使用默认模板。', 'info');
    setState(getDefaultTables());
    dispatchAllTablesUpdate();
    return getState();
}

export function saveTables(sourceAction = '未知操作') {
    log(`UI操作 "${sourceAction}" 已更新内存状态。`, 'info');
    return true;
}

// ── 渲染 wrapper（注入当前 state） ────────────────────────────────────────

export function convertTablesToCsvString() {
    let state = getState();
    if (!state) {
        loadTables();
        state = getState();
    }
    return tablesToCsv(state);
}

export function convertSelectedTablesToCsvString(selectedIndices) {
    let state = getState();
    if (!state) {
        loadTables();
        state = getState();
    }
    return tablesToCsvWithSelection(state, selectedIndices);
}

export function convertTablesToCsvStringForContentOnly() {
    return tablesToCsvContentOnly(getState());
}

// ── 模板（re-export） ─────────────────────────────────────────────────────

export const getBatchFillerRuleTemplate = _tplGetBatchFillerRuleTemplate;
export const saveBatchFillerRuleTemplate = _tplSaveBatchFillerRuleTemplate;
export const getBatchFillerFlowTemplate = _tplGetBatchFillerFlowTemplate;
export const saveBatchFillerFlowTemplate = _tplSaveBatchFillerFlowTemplate;
export const getAiFlowTemplateForInjection = _tplGetAiFlowTemplateForInjection;
export const saveAiTemplate = _tplSaveAiTemplate;
export const getAiTemplate = _tplGetAiTemplate;

// ── 文本指令应用（updateTableFromText） ───────────────────────────────────

export async function updateTableFromText(textContent, options = {}) {
    const settings = extension_settings[extensionName] || {};
    if (settings.table_system_enabled === false) {
        log('表格系统总开关已关闭，跳过 <Amily2Edit> 标签处理。', 'info');
        return;
    }

    if (!textContent) {
        log('AI返回内容为空，无法更新表格。', 'warn');
        return;
    }

    const { finalState, hasChanges, changes } = executeCommands(textContent, getState());

    if (!hasChanges) {
        log('AI指令未产生任何实质性变更。', 'info');
        return;
    }

    setState(finalState);

    if (options.immediateDelete) {
        commitPendingDeletions();
    }

    changes.forEach(change => {
        markTableUpdated(change.tableIndex);
        if (change.type === 'update' || change.type === 'insert') {
            if (change.rowIndex !== undefined && change.colIndex !== undefined) {
                addHighlight(change.tableIndex, change.rowIndex, change.colIndex);
            }
        }
    });

    log(`成功执行了 ${changes.length} 处变更。`, 'success');

    const affectedTables = [...new Set(changes.map(c => c.tableIndex))];
    affectedTables.forEach(tableIndex => dispatchTableUpdate(tableIndex));

    const context = getContext();
    if (context.chat && context.chat.length > 0) {
        const lastMessage = context.chat[context.chat.length - 1];
        if (_persistSaveStateToMessage(getState(), lastMessage)) {
            await saveChat();
            toastr.success('已根据AI的指示成功更新表格！', '填表完成');
            document.dispatchEvent(new CustomEvent('amily2-force-ui-reload'));
            return;
        }
    }

    saveChatDebounced();
    toastr.success('已根据AI的指示成功更新表格！', '填表完成');
    document.dispatchEvent(new CustomEvent('amily2-force-ui-reload'));
}

/**
 * 直接从 Operation[] 应用变更（Function Call 路径），跳过文本解析。
 * 后续流程与 updateTableFromText 完全一致。
 *
 * @param {import('./dto/Operation.js').Operation[]} ops
 * @param {Object} options - 同 updateTableFromText 的 options
 */
export async function updateTableFromOps(ops, options = {}) {
    const settings = extension_settings[extensionName] || {};
    if (settings.table_system_enabled === false) return;

    if (!Array.isArray(ops) || ops.length === 0) {
        log('Function Call 返回操作列表为空，无需更新表格。', 'info');
        return;
    }

    const { state, changes } = applyOperations(getState(), ops);

    if (changes.length === 0) {
        log('Function Call 操作未产生任何实质性变更。', 'info');
        return;
    }

    setState(state);

    if (options.immediateDelete) {
        commitPendingDeletions();
    }

    changes.forEach(change => {
        markTableUpdated(change.tableIndex);
        if (change.type === 'update' || change.type === 'insert') {
            if (change.rowIndex !== undefined && change.colIndex !== undefined) {
                addHighlight(change.tableIndex, change.rowIndex, change.colIndex);
            }
        }
    });

    log(`Function Call 成功执行了 ${changes.length} 处变更。`, 'success');

    const affectedTables = [...new Set(changes.map(c => c.tableIndex))];
    affectedTables.forEach(tableIndex => dispatchTableUpdate(tableIndex));

    const context = getContext();
    if (context.chat && context.chat.length > 0) {
        const lastMessage = context.chat[context.chat.length - 1];
        if (_persistSaveStateToMessage(getState(), lastMessage)) {
            await saveChat();
            toastr.success('已根据AI的指示成功更新表格！', '填表完成');
            document.dispatchEvent(new CustomEvent('amily2-force-ui-reload'));
            return;
        }
    }

    saveChatDebounced();
    toastr.success('已根据AI的指示成功更新表格！', '填表完成');
    document.dispatchEvent(new CustomEvent('amily2-force-ui-reload'));
}

// ── 预设（re-export 或 wrapper） ─────────────────────────────────────────

export const exportPreset = _presetExportPreset;
export const exportPresetFull = _presetExportPresetFull;
export const clearGlobalPreset = _presetClearGlobalPreset;
export const importGlobalPreset = _presetImportGlobalPreset;

/**
 * importPreset wrapper：在 setState 之后注入 SuperMemory 全量同步。
 * 兼容旧签名 importPreset(callback) 和新 importPreset({ onAfterApply, onImported })。
 */
export function importPreset(onImportedOrHooks) {
    /** @type {{ onAfterApply?: () => void, onImported?: () => void }} */
    const hooks = typeof onImportedOrHooks === 'function'
        ? { onImported: onImportedOrHooks }
        : (onImportedOrHooks || {});

    return _presetImportPreset({
        onAfterApply: () => {
            dispatchAllTablesUpdate();
            if (hooks.onAfterApply) hooks.onAfterApply();
        },
        onImported: hooks.onImported,
    });
}

// ── 回滚 ──────────────────────────────────────────────────────────────────

export async function rollbackState() {
    const context = getContext();
    if (!context || !context.chat || context.chat.length < 2) {
        log('无法回退：聊天记录不足。', 'warn');
        toastr.warning('聊天记录不足，无法执行回退操作。');
        return false;
    }

    const chat = context.chat;
    const lastMessageIndex = chat.length - 1;
    const lastMessage = chat[lastMessageIndex];

    log(`正在尝试从第 ${lastMessageIndex - 1} 条消息加载表格状态...`, 'info');
    const previousState = loadTables(lastMessageIndex);

    if (!previousState) {
        log('未能在上一楼找到可用的表格状态，无法回退。', 'error');
        toastr.error('未能在上一楼找到可用的表格状态。');
        return false;
    }

    setState(previousState);
    if (_persistSaveStateToMessage(previousState, lastMessage)) {
        await saveChat();
        log('已成功将回退后的状态保存至最新消息。', 'success');
    } else {
        log('回退状态保存失败，操作中止。', 'error');
        toastr.error('未能保存回退状态，操作中止。');
        return false;
    }

    renderTables();
    updateOrInsertTableInChat();
    log('UI已更新以显示回退后的状态。', 'info');
    return true;
}

export async function rollbackAndRefill() {
    const settings = extension_settings[extensionName] || {};
    if (settings.table_system_enabled === false) {
        log('表格系统总开关已关闭，跳过回退填表。', 'info');
        toastr.info('表格系统总开关已关闭，无法执行回退填表。');
        return;
    }

    toastr.info('正在执行回退并重新填表...');
    const rollbackSuccess = await rollbackState();

    if (!rollbackSuccess) {
        toastr.error('状态回退失败，已中止操作。');
        return;
    }

    toastr.success('状态回退成功，准备重新填表...');

    const context = getContext();
    const lastMessage = context.chat[context.chat.length - 1];

    try {
        await fillWithSecondaryApi(lastMessage, true, { targetMessage: lastMessage });
        log('回退并重新填表操作完成。', 'success');
    } catch (error) {
        log(`回退重填过程中发生错误: ${error.message}`, 'error');
        toastr.error(`重新填表失败: ${error.message}`);
    }
}

// ── 杂项 ──────────────────────────────────────────────────────────────────

export function isCurrentTablesEmpty() {
    const tables = getState();
    if (!tables || tables.length === 0) return true;
    return tables.every(table => !table.rows || table.rows.length === 0);
}

// ── 模块初始化 ─────────────────────────────────────────────────────────────

// 模块加载时执行一次初始 loadTables
loadTables();
