// ui/ocr-settings.js
// OCR 配置管理模块 - 独立于翻译配置

/**
 * OCR 设置管理器
 * 负责：
 * 1. 加载/保存 OCR 配置（独立于翻译配置）
 * 2. 引擎切换逻辑
 * 3. 首次使用提示
 */
class OcrSettingsManager {
  constructor() {
    this.BATCH_SIZE = 10; // MinerU V2 批量翻译的批次大小

    // localStorage keys（所有以 'ocr' 开头，与翻译配置隔离）
    this.keys = {
      engine: 'ocrEngine',
      // Worker Auth Key (共享)
      workerAuthKey: 'ocrWorkerAuthKey',
      // Mistral OCR
      mistralKeys: 'ocrMistralKeys',
      mistralBaseUrl: 'ocrMistralBaseUrl',
      // MinerU
      mineruToken: 'ocrMinerUToken',
      mineruWorkerUrl: 'ocrMinerUWorkerUrl',
      mineruTokenMode: 'ocrMinerUTokenMode',
      mineruEnableOcr: 'ocrMinerUEnableOcr',
      mineruEnableFormula: 'ocrMinerUEnableFormula',
      mineruEnableTable: 'ocrMinerUEnableTable',
      mineruTranslationMode: 'ocrMinerUTranslationMode', // 新增：翻译模式
      // Doc2X
      doc2xToken: 'ocrDoc2XToken',
      doc2xWorkerUrl: 'ocrDoc2XWorkerUrl',
      doc2xTokenMode: 'ocrDoc2XTokenMode',
      doc2xFormulaMode: 'ocrDoc2XFormulaMode',
      doc2xExportFormat: 'ocrDoc2XExportFormat',
      // 首次提示标记
      firstTimeTipShown: 'ocrFirstTimeTipShown'
    };

    // DOM 元素
    this.elements = {};

    this.init();
  }

  /**
   * 初始化
   */
  init() {
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', () => this.onDOMReady());
    } else {
      this.onDOMReady();
    }
  }

  /**
   * DOM 加载完成后的初始化
   */
  onDOMReady() {
    this.cacheElements();
    this.loadSettings();
    // 后端模式：异步加载 settings.ocrConfig 并应用到表单
    this._loadFromBackendIfAvailable();
    this.bindEvents();
    this.showFirstTimeTip();

    console.log('[OCR Settings] Initialized');
  }

  /**
   * 缓存 DOM 元素引用
   */
  cacheElements() {
    // OCR 引擎选择
    this.elements.ocrEngine = document.getElementById('ocrEngine');
    this.elements.localOcrHint = document.getElementById('localOcrHint');

    // Mistral OCR
    this.elements.mistralOcrKeys = document.getElementById('mistralOcrKeys');
    this.elements.mistralBaseUrl = document.getElementById('mistralBaseUrl');
    this.elements.mistralOcrConfig = document.getElementById('mistralOcrConfig');

    // MinerU
    this.elements.mineruToken = document.getElementById('mineruToken');
    this.elements.mineruWorkerUrl = document.getElementById('mineruWorkerUrl');
    this.elements.mineruEnableOcr = document.getElementById('mineruEnableOcr');
    this.elements.mineruEnableFormula = document.getElementById('mineruEnableFormula');
    this.elements.mineruEnableTable = document.getElementById('mineruEnableTable');
    this.elements.mineruOcrConfig = document.getElementById('mineruOcrConfig');
    this.elements.mineruTranslationModeConfig = document.getElementById('mineruTranslationModeConfig'); // 新增
    this.elements.mineruTranslationModeRadios = document.getElementsByName('mineruTranslationMode'); // 新增

    // Doc2X
    this.elements.doc2xToken = document.getElementById('doc2xToken');
    this.elements.doc2xWorkerUrl = document.getElementById('doc2xWorkerUrl');
    this.elements.doc2xFormulaMode = document.getElementById('doc2xFormulaMode');
    this.elements.doc2xExportFormat = document.getElementById('doc2xExportFormat');
    this.elements.doc2xOcrConfig = document.getElementById('doc2xOcrConfig');
  }

  /**
   * 加载所有 OCR 配置
   */
  loadSettings() {
    try {
      // 引擎选择
      const engine = localStorage.getItem(this.keys.engine) || 'mistral';
      if (this.elements.ocrEngine) {
        this.elements.ocrEngine.value = engine;
        this.switchEngine(engine); // 显示对应的配置面板
      }

      // Mistral OCR
      if (this.elements.mistralOcrKeys) {
        this.elements.mistralOcrKeys.value = localStorage.getItem(this.keys.mistralKeys) || '';
      }
      if (this.elements.mistralBaseUrl) {
        this.elements.mistralBaseUrl.value = localStorage.getItem(this.keys.mistralBaseUrl) || 'https://api.mistral.ai';
      }

      // MinerU
      if (this.elements.mineruToken) {
        this.elements.mineruToken.value = localStorage.getItem(this.keys.mineruToken) || '';
      }
      if (this.elements.mineruWorkerUrl) {
        this.elements.mineruWorkerUrl.value = localStorage.getItem(this.keys.mineruWorkerUrl) || '';
      }
      if (this.elements.mineruEnableOcr) {
        this.elements.mineruEnableOcr.checked = localStorage.getItem(this.keys.mineruEnableOcr) !== 'false';
      }
      if (this.elements.mineruEnableFormula) {
        this.elements.mineruEnableFormula.checked = localStorage.getItem(this.keys.mineruEnableFormula) !== 'false';
      }
      if (this.elements.mineruEnableTable) {
        this.elements.mineruEnableTable.checked = localStorage.getItem(this.keys.mineruEnableTable) !== 'false';
      }
      // 加载翻译模式
      if (this.elements.mineruTranslationModeRadios.length > 0) {
        const savedMode = localStorage.getItem(this.keys.mineruTranslationMode) || 'standard';
        Array.from(this.elements.mineruTranslationModeRadios).forEach(radio => {
          if (radio.value === savedMode) {
            radio.checked = true;
          }
        });
      }

      // Doc2X
      if (this.elements.doc2xToken) {
        this.elements.doc2xToken.value = localStorage.getItem(this.keys.doc2xToken) || '';
      }
      if (this.elements.doc2xWorkerUrl) {
        this.elements.doc2xWorkerUrl.value = localStorage.getItem(this.keys.doc2xWorkerUrl) || '';
      }
      if (this.elements.doc2xFormulaMode) {
        this.elements.doc2xFormulaMode.value = localStorage.getItem(this.keys.doc2xFormulaMode) || 'dollar';
      }
      if (this.elements.doc2xExportFormat) {
        this.elements.doc2xExportFormat.value = localStorage.getItem(this.keys.doc2xExportFormat) || '';
      }

      console.log('[OCR Settings] Settings loaded');
    } catch (error) {
      console.error('[OCR Settings] Failed to load settings:', error);
    }
  }

  /**
   * 如处于后端模式，则从后端 settings.ocrConfig 拉取配置并应用到表单，同时更新本地缓存以保持其它模块兼容。
   */
  async _loadFromBackendIfAvailable() {
    try {
      if (typeof window === 'undefined' || !window.storageAdapter || window.storageAdapter.isFrontendMode !== false) return;
      const settings = await window.storageAdapter.loadSettings();
      const cfg = (settings && settings.ocrConfig && typeof settings.ocrConfig === 'object') ? settings.ocrConfig : null;
      if (!cfg || !cfg.engine) return;

      // 将后端配置应用到 UI
      this._applyOcrConfigToDom(cfg);

      // 同步到 localStorage 以兼容其它读取路径（例如 ui_model_ocr_config.js 等）
      this._mirrorOcrConfigToLocalStorage(cfg);

      console.log('[OCR Settings] Loaded ocrConfig from backend and applied.');
    } catch (e) {
      console.warn('[OCR Settings] Failed to load ocrConfig from backend (ignored):', e?.message || e);
    }
  }

  /**
   * 将后端 ocrConfig 应用到现有表单控件
   */
  _applyOcrConfigToDom(cfg) {
    try {
      if (!cfg || !cfg.engine) return;
      if (this.elements.ocrEngine) {
        this.elements.ocrEngine.value = cfg.engine;
      }
      this.switchEngine(cfg.engine);

      const setVal = (el, val) => { if (el && val !== undefined && val !== null) el.value = String(val); };
      const setChk = (el, val) => { if (el) el.checked = !!val; };

      if (cfg.engine === 'mistral') {
        setVal(this.elements.mistralBaseUrl, cfg.baseUrl || 'https://api.mistral.ai');
        if (Array.isArray(cfg.keys)) {
          setVal(this.elements.mistralOcrKeys, cfg.keys.join('\n'));
        }
      } else if (cfg.engine === 'mineru') {
        setVal(this.elements.mineruWorkerUrl, (cfg.workerUrl || '').replace(/\/+$/, ''));
        setVal(this.elements.mineruToken, cfg.token || '');
        setVal(document.getElementById('mineruAuthKey') || null, cfg.authKey || '');
        setChk(this.elements.mineruEnableOcr, cfg.enableOcr !== false);
        setChk(this.elements.mineruEnableFormula, cfg.enableFormula !== false);
        setChk(this.elements.mineruEnableTable, cfg.enableTable !== false);
        if (this.elements.mineruTranslationModeRadios && cfg.translationMode) {
          Array.from(this.elements.mineruTranslationModeRadios).forEach(r => { r.checked = (r.value === cfg.translationMode); });
        }
      } else if (cfg.engine === 'doc2x') {
        setVal(this.elements.doc2xWorkerUrl, (cfg.workerUrl || '').replace(/\/+$/, ''));
        setVal(this.elements.doc2xToken, cfg.token || '');
        setVal(this.elements.doc2xFormulaMode, cfg.formulaMode || 'dollar');
        setVal(this.elements.doc2xExportFormat, cfg.exportFormat || '');
      }
    } catch (_) { /* ignore */ }
  }

  /**
   * 将后端 ocrConfig 写入本地存储键（用于兼容仍从 localStorage 读取的模块）
   */
  _mirrorOcrConfigToLocalStorage(cfg) {
    try {
      if (!cfg || !cfg.engine) return;
      localStorage.setItem(this.keys.engine, cfg.engine);
      if (cfg.engine === 'mistral') {
        if (Array.isArray(cfg.keys)) localStorage.setItem(this.keys.mistralKeys, cfg.keys.join('\n'));
        localStorage.setItem(this.keys.mistralBaseUrl, cfg.baseUrl || 'https://api.mistral.ai');
      } else if (cfg.engine === 'mineru') {
        localStorage.setItem(this.keys.mineruWorkerUrl, (cfg.workerUrl || '').replace(/\/+$/, ''));
        localStorage.setItem(this.keys.mineruToken, cfg.token || '');
        localStorage.setItem(this.keys.workerAuthKey, cfg.authKey || '');
        localStorage.setItem(this.keys.mineruTokenMode, cfg.tokenMode || 'frontend');
        localStorage.setItem(this.keys.mineruEnableOcr, cfg.enableOcr !== false);
        localStorage.setItem(this.keys.mineruEnableFormula, cfg.enableFormula !== false);
        localStorage.setItem(this.keys.mineruEnableTable, cfg.enableTable !== false);
        localStorage.setItem(this.keys.mineruTranslationMode, cfg.translationMode || 'standard');
      } else if (cfg.engine === 'doc2x') {
        localStorage.setItem(this.keys.doc2xWorkerUrl, (cfg.workerUrl || '').replace(/\/+$/, ''));
        localStorage.setItem(this.keys.doc2xToken, cfg.token || '');
        localStorage.setItem(this.keys.workerAuthKey, cfg.authKey || '');
        localStorage.setItem(this.keys.doc2xTokenMode, cfg.tokenMode || 'frontend');
        localStorage.setItem(this.keys.doc2xFormulaMode, cfg.formulaMode || 'dollar');
        localStorage.setItem(this.keys.doc2xExportFormat, cfg.exportFormat || '');
      }
    } catch (_) { /* ignore */ }
  }

  /**
   * 保存所有 OCR 配置
   */
  async saveSettings() {
    try {
      // 引擎选择
      if (this.elements.ocrEngine) {
        localStorage.setItem(this.keys.engine, this.elements.ocrEngine.value);
      }

      // Mistral OCR
      if (this.elements.mistralOcrKeys) {
        localStorage.setItem(this.keys.mistralKeys, this.elements.mistralOcrKeys.value);
      }
      if (this.elements.mistralBaseUrl) {
        localStorage.setItem(this.keys.mistralBaseUrl, this.elements.mistralBaseUrl.value);
      }

      // MinerU
      if (this.elements.mineruToken) {
        localStorage.setItem(this.keys.mineruToken, this.elements.mineruToken.value);
      }
      if (this.elements.mineruWorkerUrl) {
        localStorage.setItem(this.keys.mineruWorkerUrl, this.elements.mineruWorkerUrl.value);
      }
      if (this.elements.mineruEnableOcr) {
        localStorage.setItem(this.keys.mineruEnableOcr, this.elements.mineruEnableOcr.checked);
      }
      if (this.elements.mineruEnableFormula) {
        localStorage.setItem(this.keys.mineruEnableFormula, this.elements.mineruEnableFormula.checked);
      }
      if (this.elements.mineruEnableTable) {
        localStorage.setItem(this.keys.mineruEnableTable, this.elements.mineruEnableTable.checked);
      }
      // 保存翻译模式
      if (this.elements.mineruTranslationModeRadios.length > 0) {
        const checkedRadio = Array.from(this.elements.mineruTranslationModeRadios).find(r => r.checked);
        if (checkedRadio) {
          localStorage.setItem(this.keys.mineruTranslationMode, checkedRadio.value);
        }
      }

      // Doc2X
      if (this.elements.doc2xToken) {
        localStorage.setItem(this.keys.doc2xToken, this.elements.doc2xToken.value);
      }
      if (this.elements.doc2xWorkerUrl) {
        localStorage.setItem(this.keys.doc2xWorkerUrl, this.elements.doc2xWorkerUrl.value);
      }
      if (this.elements.doc2xFormulaMode) {
        localStorage.setItem(this.keys.doc2xFormulaMode, this.elements.doc2xFormulaMode.value);
      }
      if (this.elements.doc2xExportFormat) {
        localStorage.setItem(this.keys.doc2xExportFormat, this.elements.doc2xExportFormat.value);
      }

      console.log('[OCR Settings] Settings saved');

      // 后端模式：写入 settings.ocrConfig
      try {
        if (typeof window !== 'undefined' && window.storageAdapter && window.storageAdapter.isFrontendMode === false) {
          const settings = await window.storageAdapter.loadSettings();
          const cfg = this.getCurrentConfig();
          const merged = { ...(settings || {}), ocrConfig: cfg };
          await window.storageAdapter.saveSettings(merged);
          console.log('[OCR Settings] ocrConfig persisted to backend');
        }
      } catch (be) {
        console.warn('[OCR Settings] Persist ocrConfig to backend failed (ignored):', be?.message || be);
      }
    } catch (error) {
      console.error('[OCR Settings] Failed to save settings:', error);
    }
  }

  /**
   * 绑定事件监听器
   */
  bindEvents() {
    // 引擎切换
    if (this.elements.ocrEngine) {
      this.elements.ocrEngine.addEventListener('change', (e) => {
        this.switchEngine(e.target.value);
        this.saveSettings();
      });
    }

    // MinerU 翻译模式改变时自动保存
    if (this.elements.mineruTranslationModeRadios.length > 0) {
      Array.from(this.elements.mineruTranslationModeRadios).forEach(radio => {
        radio.addEventListener('change', () => this.saveSettings());
      });
    }

    // 所有输入框自动保存
    const inputIds = [
      'mistralOcrKeys', 'mistralBaseUrl',
      'mineruToken', 'mineruWorkerUrl',
      'mineruEnableOcr', 'mineruEnableFormula', 'mineruEnableTable',
      'doc2xToken', 'doc2xWorkerUrl',
      'doc2xFormulaMode', 'doc2xExportFormat'
    ];

    inputIds.forEach(id => {
      const el = this.elements[id];
      if (el) {
        el.addEventListener('change', () => this.saveSettings());

        // 对于 textarea 和 text input，也监听 input 事件（实时保存）
        if (el.tagName === 'TEXTAREA' || el.type === 'text' || el.type === 'password') {
          el.addEventListener('input', this.debounce(() => this.saveSettings(), 500));
        }
      }
    });

    console.log('[OCR Settings] Events bound');
  }

  /**
   * 切换 OCR 引擎（显示/隐藏对应配置面板）
   * @param {string} engine - 引擎名称: 'none' | 'local' | 'mistral' | 'mineru' | 'doc2x'
   */
  switchEngine(engine) {
    // 隐藏所有配置面板
    if (this.elements.mistralOcrConfig) {
      this.elements.mistralOcrConfig.classList.add('hidden');
    }
    if (this.elements.mineruOcrConfig) {
      this.elements.mineruOcrConfig.classList.add('hidden');
    }
    if (this.elements.doc2xOcrConfig) {
      this.elements.doc2xOcrConfig.classList.add('hidden');
    }

    // 隐藏 MinerU 翻译模式配置
    if (this.elements.mineruTranslationModeConfig) {
      this.elements.mineruTranslationModeConfig.classList.add('hidden');
    }

    // 隐藏本地解析提示
    if (this.elements.localOcrHint) {
      this.elements.localOcrHint.classList.add('hidden');
    }

    // 显示选中的配置面板
    switch (engine) {
      case 'none':
        // 不需要 OCR，不显示任何配置面板
        break;
      case 'local':
        // 显示本地解析提示
        if (this.elements.localOcrHint) {
          this.elements.localOcrHint.classList.remove('hidden');
        }
        break;
      case 'mistral':
        if (this.elements.mistralOcrConfig) {
          this.elements.mistralOcrConfig.classList.remove('hidden');
        }
        break;
      case 'mineru':
        if (this.elements.mineruOcrConfig) {
          this.elements.mineruOcrConfig.classList.remove('hidden');
        }
        // 显示 MinerU 翻译模式配置
        if (this.elements.mineruTranslationModeConfig) {
          this.elements.mineruTranslationModeConfig.classList.remove('hidden');
        }
        break;
      case 'doc2x':
        if (this.elements.doc2xOcrConfig) {
          this.elements.doc2xOcrConfig.classList.remove('hidden');
        }
        break;
    }

    console.log(`[OCR Settings] Switched to ${engine}`);
  }

  /**
   * 首次使用提示（可选功能）
   * 检测是否已有翻译用的 Mistral Keys，提示用户是否复制到 OCR 配置
   */
  showFirstTimeTip() {
    try {
      const ocrKeys = localStorage.getItem(this.keys.mistralKeys);
      const translationKeys = localStorage.getItem('mistralApiKeys'); // 翻译用的 Keys
      const tipShown = localStorage.getItem(this.keys.firstTimeTipShown);

      // 条件：OCR 未配置 + 翻译已配置 + 提示未显示过
      if (!ocrKeys && translationKeys && !tipShown) {
        const message =
          '检测到您已配置 Mistral 翻译 API Keys。\n\n' +
          '提示：OCR 功能使用独立的 API Key 配置。\n' +
          '是否将翻译配置复制到 OCR 配置中作为初始值？\n\n' +
          '（您可以稍后在设置中单独修改）';

        if (confirm(message)) {
          localStorage.setItem(this.keys.mistralKeys, translationKeys);
          if (this.elements.mistralOcrKeys) {
            this.elements.mistralOcrKeys.value = translationKeys;
          }
          console.log('[OCR Settings] Copied translation keys to OCR config');
        }

        // 标记提示已显示
        localStorage.setItem(this.keys.firstTimeTipShown, 'true');
      }
    } catch (error) {
      console.error('[OCR Settings] Failed to show first time tip:', error);
    }
  }

  /**
   * 获取当前选择的 OCR 引擎配置
   * @returns {Object} 配置对象
   */
  getCurrentConfig() {
    const engine = localStorage.getItem(this.keys.engine) || 'mistral';

    switch (engine) {
      case 'none':
        return { engine: 'none' };

      case 'local':
        return { engine: 'local' };

      case 'mistral':
        // 优先从 Key 管理器读取 Mistral Keys，若为空则回退到 legacy 文本框存储（ocrMistralKeys）
        try {
          const loadFn = (typeof window !== 'undefined' && typeof window.loadModelKeys === 'function')
            ? window.loadModelKeys
            : (typeof loadModelKeys === 'function' ? loadModelKeys : null);
          let keysFromManager = [];
          if (loadFn) {
            const all = loadFn('mistral') || [];
            keysFromManager = all
              .filter(k => k && k.value && k.value.trim() && (k.status === 'valid' || k.status === 'untested'))
              .map(k => k.value.trim());
          }
          const legacy = (localStorage.getItem(this.keys.mistralKeys) || '')
            .split('\n')
            .map(k => k.trim())
            .filter(Boolean);
          const merged = (keysFromManager && keysFromManager.length > 0) ? keysFromManager : legacy;
          const baseUrl = localStorage.getItem(this.keys.mistralBaseUrl) || 'https://api.mistral.ai';
          return { engine: 'mistral', keys: merged, baseUrl };
        } catch (e) {
          console.warn('[OCR Settings] 读取 Mistral Keys 失败，回退 legacy。', e);
          const legacy = (localStorage.getItem(this.keys.mistralKeys) || '')
            .split('\n')
            .map(k => k.trim())
            .filter(Boolean);
          const baseUrl = localStorage.getItem(this.keys.mistralBaseUrl) || 'https://api.mistral.ai';
          return { engine: 'mistral', keys: legacy, baseUrl };
        }

      case 'mineru':
        return {
          engine: 'mineru',
          token: localStorage.getItem(this.keys.mineruToken) || '',
          workerUrl: (localStorage.getItem(this.keys.mineruWorkerUrl) || '').replace(/\/+$/, ''), // 去掉末尾斜杠
          authKey: localStorage.getItem(this.keys.workerAuthKey) || '',
          tokenMode: localStorage.getItem(this.keys.mineruTokenMode) || 'frontend',
          enableOcr: localStorage.getItem(this.keys.mineruEnableOcr) !== 'false',
          enableFormula: localStorage.getItem(this.keys.mineruEnableFormula) !== 'false',
          enableTable: localStorage.getItem(this.keys.mineruEnableTable) !== 'false',
          translationMode: localStorage.getItem(this.keys.mineruTranslationMode) || 'standard' // 新增
        };

      case 'doc2x':
        return {
          engine: 'doc2x',
          token: localStorage.getItem(this.keys.doc2xToken) || '',
          workerUrl: (localStorage.getItem(this.keys.doc2xWorkerUrl) || '').replace(/\/+$/, ''), // 去掉末尾斜杠
          authKey: localStorage.getItem(this.keys.workerAuthKey) || '',
          tokenMode: localStorage.getItem(this.keys.doc2xTokenMode) || 'frontend',
          formulaMode: localStorage.getItem(this.keys.doc2xFormulaMode) || 'dollar',
          exportFormat: localStorage.getItem(this.keys.doc2xExportFormat) || ''
        };

      default:
        throw new Error(`Unknown OCR engine: ${engine}`);
    }
  }

  /**
   * 验证 OCR 配置是否完整
   * @returns {Object} { valid: boolean, message: string }
   */
  validateConfig() {
    const config = this.getCurrentConfig();

    switch (config.engine) {
      case 'none':
      case 'local':
        // 不需要 OCR 或本地解析，配置总是有效的
        return { valid: true, message: '' };

      case 'mistral':
        // 支持 Key 管理器 + legacy 两种来源（由 getCurrentConfig 聚合）
        if (false) {
          return { valid: false, message: '请配置 Mistral OCR API Keys' };
        }
        break;

      case 'mineru':
        // 前端透传模式需要 Token，Worker 配置模式不需要
        if (config.tokenMode === 'frontend' && !config.token) {
          return { valid: false, message: '请配置 MinerU Token（前端透传模式）' };
        }
        if (!config.workerUrl) {
          return { valid: false, message: '请配置 MinerU Worker URL' };
        }
        break;

      case 'doc2x':
        // 前端透传模式需要 Token，Worker 配置模式不需要
        if (config.tokenMode === 'frontend' && !config.token) {
          return { valid: false, message: '请配置 Doc2X Token（前端透传模式）' };
        }
        if (!config.workerUrl) {
          return { valid: false, message: '请配置 Doc2X Worker URL' };
        }
        break;
    }

    return { valid: true, message: '' };
  }

  /**
   * 防抖函数
   * @param {Function} func - 要防抖的函数
   * @param {number} wait - 等待时间（毫秒）
   * @returns {Function} 防抖后的函数
   */
  debounce(func, wait) {
    let timeout;
    return function (...args) {
      clearTimeout(timeout);
      timeout = setTimeout(() => func.apply(this, args), wait);
    };
  }
}

// 创建全局实例
if (typeof window !== 'undefined') {
  window.ocrSettingsManager = new OcrSettingsManager();
}

// 导出（如果使用模块化）
if (typeof module !== 'undefined' && module.exports) {
  module.exports = OcrSettingsManager;
}
