import type { FieldChange, FillDataResponse, FillFieldValue, RepeatRow, SourceSyncPreview, StepFillStructure, StepProgress } from '../domain/types';
import type { EditorControlEvent, OnlyOfficeBridge } from '../onlyoffice/bridge';

import { computed, ref } from 'vue';

import {
  appendRepeatRow as requestRepeatRow,
  deleteRepeatRow as requestDeleteRepeatRow,
  fetchFillData,
  previewSourceSync as requestSourceSyncPreview,
  restoreRepeatRow as requestRestoreRepeatRow,
  synchronizeSource as requestSourceSync,
} from '../api/record-fill';
import { checkboxGroupRuntimeIdentity } from '../domain/checkbox-group';
import { buildDraftFields } from '../domain/draft';
import { parsePluginContext, RECORD_FILL_BIZ_SCENE } from '../domain/plugin-context';
import { parseTag, primaryFieldTag } from '../domain/tags';
import { useFillerStore } from '../stores/record-filler';

const SDK_READY_TIMEOUT_MS = 5_000;
const DOCUMENT_CHANGE_DEBOUNCE_MS = 150;
function assignedStepId(tag: string, structure: StepFillStructure): string | undefined {
  const parsed = parseTag(tag);
  if (parsed?.type === 'repeat') return structure.repeatGroupSteps[parsed.groupCode];
  const controlTag = primaryFieldTag(tag);
  return controlTag ? structure.controlSteps[controlTag] : undefined;
}

export function useRecordFiller(bridge: OnlyOfficeBridge) {
  const store = useFillerStore();
  const recordHostContext = ref<null | { bizDataId: string; documentId: string }>(null);
  const isMultiStep = computed(() => Boolean(store.stepStructure && !store.stepStructure.configuration.singleStep));
  const currentStepId = computed(() => store.currentStepId);
  const conflictCount = computed(() => Object.keys(store.conflicts).length);
  const sourceSyncPreview = ref<null | SourceSyncPreview>(null);
  const sourceSyncLoading = ref(false);
  const visibleFields = computed(() => {
    if (!isMultiStep.value) return store.fields;
    const structure = store.stepStructure;
    if (!structure || !store.currentStepId) return [];
    return store.fields.filter((field) => assignedStepId(field.tag, structure) === store.currentStepId);
  });
  const visibleRepeatGroups = computed(() => {
    if (!isMultiStep.value) return store.repeatGroups;
    const structure = store.stepStructure;
    if (!structure || !store.currentStepId) return [];
    return store.repeatGroups.filter((group) => structure.repeatGroupSteps[group.groupCode] === store.currentStepId);
  });
  const stepProgress = computed<StepProgress[]>(() => {
    const structure = store.stepStructure;
    if (!structure) return [];
    return [...structure.configuration.steps]
      .sort((left, right) => left.order - right.order)
      .map((step) => {
        const belongsToStep = (tag: string) => {
          return assignedStepId(tag, structure) === step.id;
        };
        const stepFields = store.fields.filter((field) => {
          const tag = parseTag(field.tag);
          if (tag?.type === 'repeat') {
            return tag.rowId !== 'prototype' && structure.repeatGroupSteps[tag.groupCode] === step.id;
          }
          return belongsToStep(field.tag);
        });
        const missingFields = stepFields.filter((field) => {
          if (/^eln\.ref\./u.test(field.tag)) return false;
          const empty = field.type === 'checkbox' ? field.draftValue !== true : String(field.draftValue).trim() === '';
          return (
            field.requiredKnown === false ||
            (Boolean(field.required) && empty) ||
            field.formulaStatus === 'MISSING_INPUT' ||
            (store.formulaResultsStale && Boolean(field.formulaStatus))
          );
        }).length;
        const missingGroups = store.repeatGroups.filter(
          (group) =>
            structure.repeatGroupSteps[group.groupCode] === step.id && group.rows.filter((row) => row.status !== 'DELETE_PREPARED').length < group.minRows,
        ).length;
        const problemTags = new Set([...Object.keys(store.fieldErrors), ...Object.keys(store.conflicts)].filter(belongsToStep));
        const formulaErrorCount = stepFields.filter(
          (field) => !store.formulaResultsStale && !problemTags.has(field.tag) && field.formulaStatus === 'ERROR',
        ).length;
        const problemCount = problemTags.size + formulaErrorCount;
        const missingCount = missingFields + missingGroups;
        return {
          missingCount,
          problemCount,
          status: problemCount ? 'problem' : missingCount ? 'in-progress' : 'complete',
          step,
        };
      });
  });
  let context: null | ReturnType<typeof parsePluginContext> = null;
  let initialized = false;
  let fillData: FillDataResponse = { fields: {}, repeatGroups: [] };
  const pendingRepeatOperations = new Map<string, string>();
  const pendingDeleteOperations = new Map<string, string>();
  const pendingDeletedValues = new Map<string, FieldChange[]>();
  let sourceSyncOperationCode = '';
  const changedControls = new Map<string, string>();
  let documentChangeTimer: null | ReturnType<typeof setTimeout> = null;
  let documentWriteDepth = 0;
  function invalidateUnauthorizedContext(error: unknown): boolean {
    const status = typeof error === 'object' && error !== null && 'status' in error ? (error as { status?: unknown }).status : undefined;
    if (status !== 401 && status !== 403) return false;
    context = null;
    recordHostContext.value = null;
    sourceSyncPreview.value = null;
    sourceSyncOperationCode = '';
    store.status = 'error';
    store.message = error instanceof Error ? error.message : '填写凭证无效，请重新打开文档';
    return true;
  }
  const readyTimeout = setTimeout(() => {
    if (!initialized) {
      store.status = 'error';
      store.message = 'ONLYOFFICE SDK 初始化超时';
    }
  }, SDK_READY_TIMEOUT_MS);
  function pendingChanges(confirmedFieldCodes: string[] = []): FieldChange[] {
    return store.fields
      .filter((field) => {
        const parsed = parseTag(field.tag);
        return field.draftValue !== field.documentValue
          || (parsed && parsed.type !== 'repeat' && confirmedFieldCodes.includes(parsed.fieldCode));
      })
      .map((field) => ({ tag: field.tag, type: field.type, value: field.draftValue }));
  }
  function fieldForControlEvent(control: EditorControlEvent) {
    const tag = typeof control.Tag === 'string' ? control.Tag : '';
    const internalId = typeof control.InternalId === 'string' ? control.InternalId : '';
    if (!tag || !internalId) return undefined;
    return store.fields.find((field) => field.tag === tag && field.internalId === internalId);
  }
  function selectFieldStep(tag: string) {
    const structure = store.stepStructure;
    if (!structure) return;
    const stepId = assignedStepId(tag, structure);
    if (stepId) store.selectStep(stepId);
  }
  async function flushDocumentChanges() {
    documentChangeTimer = null;
    if (documentWriteDepth) {
      scheduleDocumentChanges();
      return;
    }
    const expected = new Map(changedControls);
    changedControls.clear();
    try {
      const fields = await bridge.inspectFields();
      const selectedTargets = new Map<string, string[]>();
      for (const [tag, internalId] of expected) {
        const next = fields.find((field) => field.tag === tag && field.internalId === internalId);
        const current = store.fields.find((field) => field.tag === tag && field.internalId === internalId);
        if (!next || !current || next.type !== current.type) continue;
        if (current.type === 'checkbox' && current.documentValue === false && next.currentValue === true) {
          const identity = checkboxGroupRuntimeIdentity(current, store.stepStructure);
          if (identity) selectedTargets.set(identity, [...(selectedTargets.get(identity) ?? []), tag]);
        }
        store.syncDocumentField(tag, next.currentValue);
      }
      const correctedTags = new Set<string>();
      for (const [identity, targetTags] of selectedTargets) {
        if (targetTags.length !== 1) continue;
        const target = store.fields.find((field) => field.tag === targetTags[0]);
        if (!target) continue;
        const accepted = store.setDraft(target.tag, true);
        if (!accepted) {
          const notice = store.checkboxGroupNotice;
          store.setDraft(target.tag, false);
          store.checkboxGroupNotice = notice;
        }
        for (const candidate of store.fields) {
          if (checkboxGroupRuntimeIdentity(candidate, store.stepStructure) !== identity) continue;
          if (candidate.draftValue !== candidate.documentValue) correctedTags.add(candidate.tag);
        }
      }
      const changes = [...correctedTags]
        .flatMap((tag) => {
          const field = store.fields.find((item) => item.tag === tag);
          return field && field.draftValue !== field.documentValue
            ? [{ tag: field.tag, type: field.type, value: field.draftValue }]
            : [];
        });
      if (changes.length) {
        const results = await applyDocumentFields(changes);
        store.applyResults(results, { preserveExistingErrors: true });
        if (!results.every((result) => result.ok)) {
          const verifiedFields = await bridge.inspectFields();
          for (const change of changes) {
            const verified = verifiedFields.find((field) => field.tag === change.tag);
            const current = store.fields.find((field) => field.tag === change.tag);
            if (verified && current && verified.type === current.type) {
              store.syncDocumentField(change.tag, verified.currentValue);
            }
          }
        }
      }
      store.documentSyncError = '';
    } catch (error) {
      store.documentSyncError = error instanceof Error ? error.message : String(error);
    } finally {
      if (changedControls.size) scheduleDocumentChanges();
    }
  }
  function scheduleDocumentChanges() {
    if (documentChangeTimer) clearTimeout(documentChangeTimer);
    documentChangeTimer = setTimeout(() => void flushDocumentChanges(), DOCUMENT_CHANGE_DEBOUNCE_MS);
  }
  function onControlChanged(control: EditorControlEvent) {
    const field = fieldForControlEvent(control);
    if (!field) return;
    changedControls.set(field.tag, field.internalId);
    scheduleDocumentChanges();
  }
  function onControlFocused(control: EditorControlEvent) {
    const field = fieldForControlEvent(control);
    if (!field) return;
    store.focusedTag = field.tag;
    selectFieldStep(field.tag);
  }
  async function applyDocumentFields(changes: FieldChange[]) {
    documentWriteDepth += 1;
    try {
      return await bridge.applyFields(changes);
    } catch (error) {
      const message = error instanceof Error ? error.message : String(error);
      store.fieldErrors = Object.fromEntries(changes.map((change) => [change.tag, message]));
      throw error;
    } finally {
      documentWriteDepth -= 1;
      if (!documentWriteDepth && changedControls.size) scheduleDocumentChanges();
    }
  }
  const pendingCount = computed(() => pendingChanges().length);
  const canSynchronizeSource = computed(() => {
    const initializedStatus = store.status;
    return Boolean(initializedStatus !== 'initializing' && context?.canFill && context.bizScene === RECORD_FILL_BIZ_SCENE);
  });
  const recordHostState = computed(() => {
    if (!recordHostContext.value) return null;
    return {
      bizDataId: recordHostContext.value.bizDataId,
      documentId: recordHostContext.value.documentId,
      pendingCount: pendingCount.value,
      type: 'jnpf:eln-record-fill-state' as const,
      version: 1 as const,
    };
  });
  async function initialize() {
    initialized = true;
    clearTimeout(readyTimeout);
    try {
      context = parsePluginContext(bridge.getRuntimeOptions());
      recordHostContext.value = context.bizScene === RECORD_FILL_BIZ_SCENE ? { bizDataId: context.bizDataId, documentId: context.documentId } : null;
      if (context.bizScene === RECORD_FILL_BIZ_SCENE && context.canFill) {
        await bridge.setFillOnlyMode(true);
      }
      const [data, fields] = await Promise.all([fetchFillData(context), bridge.inspectFields()]);
      const pendingSync = data.pendingSourceSync;
      fillData = data;
      store.repeatGroups = data.repeatGroups;
      store.setStepStructure(data.stepStructure);
      for (const group of data.repeatGroups) {
        for (const row of group.rows) {
          if (row.deleteOperationCode) pendingDeleteOperations.set(repeatRowKey(group.groupCode, row.rowId), row.deleteOperationCode);
        }
      }
      store.fields = buildDraftFields(fields, data, { ignoreDataValues: true });
      store.refreshCheckboxGroupError();
      if (!store.checkboxGroupError) {
        store.fields = buildDraftFields(fields, data, { preferData: context.bizScene === RECORD_FILL_BIZ_SCENE });
        store.refreshCheckboxGroupError();
      }
      if (context.bizScene === RECORD_FILL_BIZ_SCENE && context.canFill && !store.checkboxGroupError) {
        const changes = pendingChanges(pendingSync?.changedFieldCodes);
        if (changes.length) {
          const results = await applyDocumentFields(changes);
          store.applyResults(results);
          if (!results.every((item) => item.ok)) {
            store.status = 'error';
            store.message = '数据库当前态恢复到文档失败';
            return;
          }
        }
      }
      store.status = 'ready';
      store.message = pendingSync && context.canFill
        ? '来源同步已恢复，等待文档保存确认'
        : context.canFill ? '已连接' : '当前记录仅可查看';
    } catch (error) {
      if (!invalidateUnauthorizedContext(error)) {
        store.status = 'error';
        store.message = error instanceof Error ? error.message : String(error);
      }
    }
  }
  async function apply() {
    if (!context?.canFill) return;
    if (conflictCount.value || store.checkboxGroupError) return;
    const changes = pendingChanges();
    if (!changes.length) return;
    store.status = 'working';
    try {
      const results = await applyDocumentFields(changes);
      store.applyResults(results);
      store.status = 'ready';
      store.message = results.every((item) => item.ok) ? '已应用到文档' : '部分字段应用失败';
    } catch (error) {
      store.status = 'error';
      store.message = error instanceof Error ? error.message : String(error);
    }
  }
  async function previewSourceSync() {
    if (!context || !canSynchronizeSource.value || store.status !== 'ready') return;
    sourceSyncLoading.value = true;
    store.status = 'working';
    store.sourceSyncError = '';
    try {
      sourceSyncPreview.value = await requestSourceSyncPreview(context);
      sourceSyncOperationCode = '';
      store.message = sourceSyncPreview.value.changedCount ? '来源快照差异已加载' : '来源快照没有变化';
    } catch (error) {
      store.sourceSyncError = error instanceof Error ? error.message : String(error);
      if (!invalidateUnauthorizedContext(error)) store.message = '来源快照差异加载失败';
    } finally {
      if (context) store.status = 'ready';
      sourceSyncLoading.value = false;
    }
  }
  function synchronizedValue(tag: string, data: FillDataResponse): FillFieldValue | undefined {
    const source = data.fields[primaryFieldTag(tag) ?? ''];
    const field = store.fields.find((item) => item.tag === tag);
    if (!source || !field || source.type !== field.type) return undefined;
    if (field.type === 'checkbox') return Boolean(source.value);
    return typeof source.value === 'string' ? source.value : '';
  }
  function mergeSynchronizedFields(data: FillDataResponse, changedFieldCodes: Set<string>): FieldChange[] {
    const changes: FieldChange[] = [];
    for (const field of store.fields) {
      const parsed = parseTag(field.tag);
      if (!parsed || parsed.type === 'repeat' || !changedFieldCodes.has(parsed.fieldCode)) continue;
      const value = synchronizedValue(field.tag, data);
      if (value === undefined) throw new Error(`同步后填写数据缺少来源字段：${field.alias}`);
      const metadata = data.fields[primaryFieldTag(field.tag) ?? ''];
      field.draftValue = value;
      field.required = metadata?.required === true;
      field.requiredKnown = Boolean(metadata);
      field.formulaStatus = metadata?.formulaStatus;
      field.formulaMessage = metadata?.formulaMessage;
      delete store.conflicts[field.tag];
      // A metadata-only clear still needs a document save callback to confirm the operation.
      changes.push({ tag: field.tag, type: field.type, value });
    }
    return changes;
  }
  async function synchronizeSource(clearReasons: Record<string, string> = {}) {
    const preview = sourceSyncPreview.value;
    if (!context || !preview || !canSynchronizeSource.value || store.status !== 'ready'
      || (!preview.changedCount && !Object.keys(clearReasons).length)) return;
    sourceSyncLoading.value = true;
    store.status = 'working';
    store.sourceSyncError = '';
    let synchronized = false;
    try {
      sourceSyncOperationCode ||= createOperationCode('source-sync');
      const syncResult = await requestSourceSync(context, {
        expectedRecordVersion: preview.recordVersion,
        operationCode: sourceSyncOperationCode,
        previewToken: preview.previewToken,
        ...(Object.keys(clearReasons).length ? { clearReasons } : {}),
      });
      synchronized = true;
      const nextData = await fetchFillData(context);
      const changedFieldCodes = new Set(syncResult.changedFieldCodes);
      const changes = mergeSynchronizedFields(nextData, changedFieldCodes);
      fillData = nextData;
      if (changes.length) {
        const results = await applyDocumentFields(changes);
        store.applyResults(results);
        if (!results.every((item) => item.ok)) {
          throw new Error('部分来源字段写入文档失败，请重试应用');
        }
      }
      store.formulaResultsStale = false;
      sourceSyncPreview.value = null;
      sourceSyncOperationCode = '';
      store.message = '来源快照已写入文档，等待保存确认';
    } catch (error) {
      const message = error instanceof Error ? error.message : String(error);
      store.sourceSyncError = synchronized ? `来源快照已同步，但${message}` : message;
      if (!invalidateUnauthorizedContext(error)) {
        store.message = synchronized ? '来源快照已同步，文档刷新失败' : '来源快照同步失败';
      }
    } finally {
      if (context) store.status = 'ready';
      sourceSyncLoading.value = false;
    }
  }
  function createOperationCode(prefix = 'repeat'): string {
    const uuid = globalThis.crypto?.randomUUID?.();
    return `${prefix}-${uuid || `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}`;
  }
  function repeatRowKey(groupCode: string, rowId: string): string {
    return `${groupCode}\n${rowId}`;
  }
  function replaceRepeatRow(row: RepeatRow) {
    const group = store.repeatGroups.find((item) => item.groupCode === row.groupCode);
    if (!group) return;
    const index = group.rows.findIndex((item) => item.rowId === row.rowId);
    if (index >= 0) group.rows[index] = row;
    else group.rows.push(row);
    group.rows.sort((left, right) => left.rowOrder - right.rowOrder);
    group.activeRowCount = group.rows.length;
  }
  async function applyPendingChanges(): Promise<void> {
    if (conflictCount.value) throw new Error('请先处理字段冲突');
    if (store.checkboxGroupError) throw new Error('请先处理选择组错误');
    const changes = pendingChanges();
    if (!changes.length) return;
    const results = await applyDocumentFields(changes);
    store.applyResults(results);
    if (!results.every((item) => item.ok)) throw new Error('请先处理字段应用失败后再新增行');
  }
  async function appendRepeatRow(groupCode: string) {
    if (!context?.canFill || context.bizScene !== RECORD_FILL_BIZ_SCENE || !groupCode || store.status !== 'ready') return;
    store.status = 'working';
    store.repeatError = '';
    try {
      await applyPendingChanges();
      const operationCode = pendingRepeatOperations.get(groupCode) || createOperationCode();
      pendingRepeatOperations.set(groupCode, operationCode);
      const row = await requestRepeatRow(context, { groupCode, operationCode });
      if (row.groupCode !== groupCode || !row.rowId) throw new Error('新增重复行响应与请求不一致');
      await bridge.appendRepeatRow(groupCode, row.rowId);
      const fields = await bridge.inspectFields();
      replaceRepeatRow(row);
      store.formulaResultsStale = true;
      store.fields = buildDraftFields(fields, { ...fillData, repeatGroups: store.repeatGroups }, { ignoreDataValues: true });
      store.refreshCheckboxGroupError();
      store.fieldErrors = {};
      store.repeatError = '';
      pendingRepeatOperations.delete(groupCode);
      store.status = 'ready';
      store.message = `已新增第 ${row.rowOrder} 行`;
    } catch (error) {
      store.repeatError = error instanceof Error ? error.message : String(error);
      if (!invalidateUnauthorizedContext(error)) {
        store.status = 'ready';
        store.message = '新增重复行失败，可重试';
      }
    }
  }
  async function deleteRepeatRow(groupCode: string, rowId: string, reason: string) {
    if (!context?.canFill || context.bizScene !== RECORD_FILL_BIZ_SCENE || store.status !== 'ready') return;
    const normalizedReason = reason.trim();
    if (!normalizedReason) {
      store.repeatError = '删除原因不能为空';
      return;
    }
    store.status = 'working';
    store.repeatError = '';
    const key = repeatRowKey(groupCode, rowId);
    const metadata = store.repeatGroups.find((group) => group.groupCode === groupCode)?.rows.find((row) => row.rowId === rowId);
    const operationCode = pendingDeleteOperations.get(key) || metadata?.deleteOperationCode || createOperationCode();
    pendingDeleteOperations.set(key, operationCode);
    try {
      await applyPendingChanges();
      const prefix = `eln.repeat.${groupCode}.${rowId}.`;
      const rowSnapshot = store.fields
        .filter((field) => field.tag.startsWith(prefix))
        .map((field) => ({ tag: field.tag, type: field.type, value: field.draftValue }));
      const prepared = await requestDeleteRepeatRow(context, { groupCode, operationCode, reason: normalizedReason, rowId });
      replaceRepeatRow(prepared);
      store.formulaResultsStale = true;
      try {
        await bridge.removeRepeatRow(groupCode, rowId);
      } catch (documentError) {
        try {
          const restored = await requestRestoreRepeatRow(context, { groupCode, operationCode, rowId });
          replaceRepeatRow(restored);
        } catch (restoreError) {
          if (invalidateUnauthorizedContext(restoreError)) throw restoreError;
          const restoreMessage = restoreError instanceof Error ? restoreError.message : String(restoreError);
          throw new Error(`${documentError instanceof Error ? documentError.message : String(documentError)}；服务端恢复失败：${restoreMessage}`);
        }
        throw documentError;
      }
      pendingDeletedValues.set(key, rowSnapshot);
      const fields = await bridge.inspectFields();
      store.fields = buildDraftFields(fields, { ...fillData, repeatGroups: store.repeatGroups }, { ignoreDataValues: true });
      store.refreshCheckboxGroupError();
      store.status = 'ready';
      store.message = '重复行已标记删除，保存文档后生效';
    } catch (error) {
      store.repeatError = error instanceof Error ? error.message : String(error);
      if (!invalidateUnauthorizedContext(error)) {
        store.status = 'ready';
        store.message = '删除重复行失败，可重试';
      }
    }
  }
  async function restoreRepeatRow(groupCode: string, rowId: string) {
    if (!context?.canFill || context.bizScene !== RECORD_FILL_BIZ_SCENE || store.status !== 'ready') return;
    const metadata = store.repeatGroups.find((group) => group.groupCode === groupCode)?.rows.find((row) => row.rowId === rowId);
    const operationCode = metadata?.deleteOperationCode || pendingDeleteOperations.get(repeatRowKey(groupCode, rowId));
    if (!metadata || metadata.status !== 'DELETE_PREPARED' || !operationCode) {
      store.repeatError = '待恢复重复行状态无效';
      return;
    }
    store.status = 'working';
    store.repeatError = '';
    const key = repeatRowKey(groupCode, rowId);
    try {
      const prefix = `eln.repeat.${groupCode}.${rowId}.`;
      if (!store.fields.some((field) => field.tag.startsWith(prefix))) {
        const group = store.repeatGroups.find((item) => item.groupCode === groupCode);
        const nextRow = group?.rows
          .filter((row) => row.rowOrder > metadata.rowOrder && store.fields.some((field) => field.tag.startsWith(`eln.repeat.${groupCode}.${row.rowId}.`)))
          .sort((left, right) => left.rowOrder - right.rowOrder)[0];
        if (nextRow) await bridge.appendRepeatRow(groupCode, rowId, nextRow.rowId);
        else await bridge.appendRepeatRow(groupCode, rowId);
        const fields = await bridge.inspectFields();
        const restoredFields = buildDraftFields(fields, fillData, { preferData: true });
        const cachedValues = pendingDeletedValues.get(key);
        let changes: FieldChange[];
        if (cachedValues) {
          changes = cachedValues
            .map((change) => {
              const field = restoredFields.find((item) => item.tag === change.tag && item.type === change.type);
              if (!field) throw new Error('恢复重复行字段结构与删除前不一致');
              field.draftValue = change.value;
              return change;
            })
            .filter((change) => restoredFields.find((field) => field.tag === change.tag)?.documentValue !== change.value);
        } else {
          changes = restoredFields
            .filter((field) => field.tag.startsWith(prefix) && field.draftValue !== field.documentValue)
            .map((field) => ({ tag: field.tag, type: field.type, value: field.draftValue }));
        }
        if (changes.length) {
          const results = await applyDocumentFields(changes);
          store.fieldErrors = Object.fromEntries(results.filter((result) => !result.ok).map((result) => [result.tag, result.error || '应用失败']));
          for (const result of results) {
            const field = restoredFields.find((item) => item.tag === result.tag);
            if (field && result.ok) field.documentValue = field.draftValue;
          }
          if (!results.every((item) => item.ok)) throw new Error('恢复重复行字段值失败');
        }
        store.fields = restoredFields;
        store.refreshCheckboxGroupError();
      }
      const restored = await requestRestoreRepeatRow(context, { groupCode, operationCode, rowId });
      replaceRepeatRow(restored);
      store.formulaResultsStale = true;
      pendingDeletedValues.delete(key);
      pendingDeleteOperations.delete(key);
      store.status = 'ready';
      store.message = '重复行已恢复';
    } catch (error) {
      store.repeatError = error instanceof Error ? error.message : String(error);
      if (!invalidateUnauthorizedContext(error)) {
        store.status = 'ready';
        store.message = '恢复重复行失败，可重试';
      }
    }
  }
  async function focusField(tag: string) {
    const field = store.fields.find((item) => item.tag === tag);
    if (!field) return;
    try {
      await bridge.selectControl(field.internalId);
      store.focusedTag = field.tag;
      selectFieldStep(field.tag);
      store.documentSyncError = '';
    } catch (error) {
      store.documentSyncError = error instanceof Error ? error.message : String(error);
    }
  }
  async function focusFirstFieldInStep(stepId: string) {
    const structure = store.stepStructure;
    if (!structure) return;
    const field = store.fields.find((item) => {
      const parsed = parseTag(item.tag);
      return parsed && parsed.type !== 'reference' && assignedStepId(item.tag, structure) === stepId;
    });
    if (field) await focusField(field.tag);
  }
  const cleanup = bridge.bindLifecycle({
    onControlChanged,
    onControlFocused,
    onReady: () => void initialize(),
    onThemeChanged: () => undefined,
  });
  return {
    store,
    apply,
    appendRepeatRow,
    deleteRepeatRow,
    dispose: () => {
      clearTimeout(readyTimeout);
      if (documentChangeTimer) clearTimeout(documentChangeTimer);
      cleanup();
    },
    canFill: () => Boolean(context?.canFill),
    canSynchronizeSource,
    currentStepId,
    conflictCount,
    focusField,
    focusFirstFieldInStep,
    isMultiStep,
    pendingCount,
    recordHostState,
    previewSourceSync,
    selectStep: (stepId: string) => store.selectStep(stepId),
    stepProgress,
    sourceSyncLoading,
    sourceSyncPreview,
    synchronizeSource,
    visibleFields,
    visibleRepeatGroups,
    canAppendRepeat: (groupCode?: string) => {
      if (!context?.canFill || context.bizScene !== RECORD_FILL_BIZ_SCENE) return false;
      const group = groupCode ? store.repeatGroups.find((item) => item.groupCode === groupCode) : undefined;
      return !group || group.activeRowCount < group.maxRows;
    },
    restoreRepeatRow,
  };
}
