(function attachBackgroundAccountRunHistory(root, factory) {
  root.MultiPageBackgroundAccountRunHistory = factory();
})(typeof self !== 'undefined' ? self : globalThis, function createBackgroundAccountRunHistoryModule() {
  function createAccountRunHistoryHelpers(deps = {}) {
    const {
      ACCOUNT_RUN_HISTORY_STORAGE_KEY = 'accountRunHistory',
      addLog,
      buildLocalHelperEndpoint,
      chrome,
      getErrorMessage,
      getState,
      normalizeAccountRunHistoryHelperBaseUrl,
    } = deps;

    function normalizeTimestamp(value) {
      const timestamp = Date.parse(String(value || ''));
      return Number.isFinite(timestamp) ? timestamp : 0;
    }

    function normalizeRetryCount(value) {
      const count = Math.floor(Number(value) || 0);
      return count > 0 ? count : 0;
    }

    function normalizeFinalStatus(status = '') {
      const normalized = String(status || '').trim().toLowerCase();
      if (!normalized) {
        return '';
      }
      if (normalized === 'success') {
        return 'success';
      }
      if (normalized === 'failed' || /_failed$/.test(normalized)) {
        return 'failed';
      }
      if (normalized === 'stopped' || /_stopped$/.test(normalized)) {
        return 'stopped';
      }
      return '';
    }

    function extractRecordStepFromStatus(status = '') {
      const normalizedStatus = String(status || '').trim().toLowerCase();
      const statusMatch = normalizedStatus.match(/^step(\d+)_(?:failed|stopped)$/);
      if (statusMatch) {
        const step = Number(statusMatch[1]);
        return Number.isInteger(step) && step > 0 ? step : null;
      }

      return null;
    }

    function extractRecordStepFromDetailPrefix(detail = '') {
      const text = String(detail || '').trim();
      const detailMatch = text.match(/^(?:Step\s+(\d+)|步骤\s*(\d+))\s*(?::|：|失败|停止|已|\b)/i);
      if (!detailMatch) {
        return null;
      }

      const step = Number(detailMatch[1] || detailMatch[2]);
      return Number.isInteger(step) && step > 0 ? step : null;
    }

    function extractAnyRecordStepFromDetail(detail = '') {
      const text = String(detail || '').trim();
      const detailMatch = text.match(/(?:Step\s+(\d+)|步骤\s*(\d+))/i);
      if (!detailMatch) {
        return null;
      }

      const step = Number(detailMatch[1] || detailMatch[2]);
      return Number.isInteger(step) && step > 0 ? step : null;
    }

    function extractRecordStep(status = '', detail = '') {
      return extractRecordStepFromStatus(status) || extractRecordStepFromDetailPrefix(detail);
    }

    function parseFailureLabelStep(label = '') {
      const match = String(label || '').trim().match(/^步骤\s*(\d+)\s*(?:失败|停止)$/);
      if (!match) {
        return null;
      }
      const step = Number(match[1]);
      return Number.isInteger(step) && step > 0 ? step : null;
    }

    function shouldIgnorePersistedFailedStepCandidate(candidate, failureDetail = '') {
      if (!Number.isInteger(candidate) || candidate <= 0) {
        return true;
      }

      const text = String(failureDetail || '').trim();
      if (!text) {
        return false;
      }

      const leadingStep = extractRecordStepFromDetailPrefix(text);
      if (Number.isInteger(leadingStep) && leadingStep > 0) {
        return leadingStep !== candidate;
      }

      const incidentalStep = extractAnyRecordStepFromDetail(text);
      return incidentalStep === candidate;
    }

    function resolveNormalizedFailedStep(record = {}, failureDetail = '') {
      const explicitStatusStep = extractRecordStepFromStatus(record.finalStatus || record.status || '');
      if (Number.isInteger(explicitStatusStep) && explicitStatusStep > 0) {
        return explicitStatusStep;
      }

      const detailStep = extractRecordStepFromDetailPrefix(failureDetail);
      if (Number.isInteger(detailStep) && detailStep > 0) {
        return detailStep;
      }

      const failedStepCandidate = Number(record.failedStep);
      if (Number.isInteger(failedStepCandidate)
        && failedStepCandidate > 0
        && !shouldIgnorePersistedFailedStepCandidate(failedStepCandidate, failureDetail)) {
        return failedStepCandidate;
      }

      return null;
    }

    function resolveFailureLabel(finalStatus, rawFailureLabel = '', computedFailureLabel = '', failedStep = null) {
      const rawLabel = String(rawFailureLabel || '').trim();
      if (finalStatus === 'stopped') {
        return computedFailureLabel;
      }
      if (finalStatus !== 'failed') {
        return rawLabel || computedFailureLabel;
      }

      const rawStep = parseFailureLabelStep(rawLabel);
      if (Number.isInteger(rawStep) && rawStep > 0) {
        return rawStep === failedStep ? rawLabel : computedFailureLabel;
      }

      return rawLabel || computedFailureLabel;
    }

    function isPhoneVerificationFailure(detail = '') {
      const text = String(detail || '').trim();
      if (!text) {
        return false;
      }

      return /add[_\s-]?phone/i.test(text)
        || /手机号(?:验证|页面|页)|手机(?:号)?页面|出现手机号验证/.test(text)
        || /进入了手机号页面/.test(text);
    }

    function buildFailureLabel(finalStatus, failedStep, failureDetail = '') {
      if (finalStatus === 'success') {
        return '流程完成';
      }
      if (finalStatus === 'stopped') {
        if (Number.isInteger(failedStep) && failedStep > 0) {
          return `步骤 ${failedStep} 停止`;
        }
        return '流程已停止';
      }
      if (finalStatus !== 'failed') {
        return '无';
      }
      if (isPhoneVerificationFailure(failureDetail)) {
        return '出现手机号验证';
      }
      if (Number.isInteger(failedStep) && failedStep > 0) {
        return `步骤 ${failedStep} 失败`;
      }
      return '流程失败';
    }

    function normalizeAccountIdentifierType(value = '') {
      return String(value || '').trim().toLowerCase() === 'phone' ? 'phone' : 'email';
    }

    function normalizeAccountIdentifierValue(value = '', identifierType = 'email') {
      const normalizedValue = String(value || '').trim();
      if (!normalizedValue) {
        return '';
      }
      return normalizeAccountIdentifierType(identifierType) === 'phone'
        ? normalizedValue
        : normalizedValue.toLowerCase();
    }

    function getActivationPhoneNumber(activation = null) {
      if (!activation || typeof activation !== 'object' || Array.isArray(activation)) {
        return '';
      }
      return String(
        activation.phoneNumber
        ?? activation.number
        ?? activation.phone
        ?? ''
      ).trim();
    }

    function resolveStatePhoneNumber(state = {}) {
      const identifierType = String(state?.accountIdentifierType || '').trim().toLowerCase();
      const accountIdentifierPhone = identifierType === 'phone'
        ? String(state?.accountIdentifier || '').trim()
        : '';

      return String(
        state?.phoneNumber
        || state?.signupPhoneNumber
        || accountIdentifierPhone
        || getActivationPhoneNumber(state?.signupPhoneCompletedActivation)
        || getActivationPhoneNumber(state?.signupPhoneActivation)
        || getActivationPhoneNumber(state?.currentPhoneActivation)
        || ''
      ).trim();
    }

    function normalizePhoneRecordKey(value = '') {
      const rawValue = String(value || '').trim();
      const digits = rawValue.replace(/\D+/g, '');
      return digits || rawValue.toLowerCase();
    }

    function resolveRecordIdentity(record = {}) {
      const rawEmail = String(record.email || '').trim().toLowerCase();
      const rawPhoneNumber = String(record.phoneNumber ?? record.phone ?? record.number ?? '').trim();
      const rawIdentifierType = String(record.accountIdentifierType || '').trim().toLowerCase();
      const inferredIdentifierType = rawIdentifierType === 'phone'
        ? 'phone'
        : (rawIdentifierType === 'email'
          ? 'email'
          : ((!rawEmail && rawPhoneNumber) ? 'phone' : 'email'));
      const rawAccountIdentifier = String(
        record.accountIdentifier
        || (inferredIdentifierType === 'phone' ? rawPhoneNumber : rawEmail)
        || ''
      ).trim();
      const accountIdentifierType = rawAccountIdentifier
        ? normalizeAccountIdentifierType(inferredIdentifierType)
        : (rawEmail ? 'email' : (rawPhoneNumber ? 'phone' : ''));
      const accountIdentifier = normalizeAccountIdentifierValue(
        rawAccountIdentifier || (accountIdentifierType === 'phone' ? rawPhoneNumber : rawEmail),
        accountIdentifierType || inferredIdentifierType
      );
      const email = rawEmail || (accountIdentifierType === 'email' ? accountIdentifier : '');
      const phoneNumber = rawPhoneNumber || (accountIdentifierType === 'phone' ? accountIdentifier : '');

      return {
        email,
        phoneNumber,
        accountIdentifierType,
        accountIdentifier,
      };
    }

    function buildRecordId(identifier = '', identifierType = 'email') {
      const normalizedIdentifierType = normalizeAccountIdentifierType(identifierType);
      const normalizedIdentifier = normalizeAccountIdentifierValue(identifier, normalizedIdentifierType);
      if (!normalizedIdentifier) {
        return '';
      }
      if (normalizedIdentifierType === 'phone' && /^phone:/i.test(normalizedIdentifier)) {
        return normalizedIdentifier.toLowerCase();
      }
      return normalizedIdentifierType === 'phone'
        ? `phone:${normalizedIdentifier.toLowerCase()}`
        : normalizedIdentifier;
    }

    function normalizeSource(value = '') {
      return String(value || '').trim().toLowerCase() === 'auto' ? 'auto' : 'manual';
    }

    function normalizeAutoRunContext(context) {
      if (!context || typeof context !== 'object') {
        return null;
      }

      const currentRun = Math.max(0, Math.floor(Number(context.currentRun) || 0));
      const totalRuns = Math.max(0, Math.floor(Number(context.totalRuns) || 0));
      const attemptRun = Math.max(0, Math.floor(Number(context.attemptRun) || 0));

      if (!currentRun && !totalRuns && !attemptRun) {
        return null;
      }

      return {
        currentRun,
        totalRuns,
        attemptRun,
      };
    }

    function buildAutoRunContextFromState(state = {}) {
      return normalizeAutoRunContext({
        currentRun: state.autoRunCurrentRun,
        totalRuns: state.autoRunTotalRuns,
        attemptRun: state.autoRunAttemptRun,
      });
    }

    function getRetryCountFromState(state = {}) {
      if (!Boolean(state.autoRunning)) {
        return 0;
      }

      const attemptRun = Math.max(0, Math.floor(Number(state.autoRunAttemptRun) || 0));
      return attemptRun > 1 ? attemptRun - 1 : 0;
    }

    function normalizeAccountRunHistoryRecord(record) {
      if (!record || typeof record !== 'object') {
        return null;
      }

      const identity = resolveRecordIdentity(record);
      const email = identity.email;
      const phoneNumber = identity.phoneNumber;
      const accountIdentifierType = identity.accountIdentifierType;
      const accountIdentifier = identity.accountIdentifier;
      const password = String(record.password ?? '').trim();
      const finalStatus = normalizeFinalStatus(record.finalStatus || record.status || '');

      if (!accountIdentifier || !finalStatus) {
        return null;
      }

      const finishedAt = String(record.finishedAt || record.recordedAt || '').trim();
      const failureDetail = finalStatus === 'failed' || finalStatus === 'stopped'
        ? String(record.failureDetail || record.reason || '').trim()
        : '';
      const failedStep = finalStatus === 'failed' || finalStatus === 'stopped'
        ? resolveNormalizedFailedStep(record, failureDetail)
        : null;
      const autoRunContext = normalizeAutoRunContext(record.autoRunContext);
      const retryCount = normalizeRetryCount(
        record.retryCount !== undefined
          ? record.retryCount
          : ((autoRunContext?.attemptRun || 0) > 1 ? autoRunContext.attemptRun - 1 : 0)
      );
      const source = normalizeSource(record.source || (autoRunContext ? 'auto' : 'manual'));
      const computedFailureLabel = buildFailureLabel(finalStatus, failedStep, failureDetail);
      const rawFailureLabel = String(record.failureLabel || '').trim();

      return {
        recordId: String(record.recordId || '').trim() || buildRecordId(accountIdentifier, accountIdentifierType),
        accountIdentifierType,
        accountIdentifier,
        email,
        phoneNumber,
        password,
        finalStatus,
        finishedAt,
        retryCount,
        failureLabel: resolveFailureLabel(finalStatus, rawFailureLabel, computedFailureLabel, failedStep),
        failureDetail,
        failedStep: Number.isInteger(failedStep) && failedStep > 0 ? failedStep : null,
        source,
        autoRunContext: source === 'auto' ? autoRunContext : null,
        plusModeEnabled: Boolean(record.plusModeEnabled),
        contributionMode: Boolean(record.contributionMode),
      };
    }

    function normalizeAccountRunHistory(records) {
      if (!Array.isArray(records)) {
        return [];
      }

      return records
        .map((item) => normalizeAccountRunHistoryRecord(item))
        .filter(Boolean)
        .sort((left, right) => normalizeTimestamp(right.finishedAt) - normalizeTimestamp(left.finishedAt));
    }

    async function getPersistedAccountRunHistory() {
      try {
        const stored = await chrome.storage.local.get(ACCOUNT_RUN_HISTORY_STORAGE_KEY);
        return normalizeAccountRunHistory(stored[ACCOUNT_RUN_HISTORY_STORAGE_KEY]);
      } catch (err) {
        console.warn('[MultiPage:account-run-history] Failed to read account run history:', err?.message || err);
        return [];
      }
    }

    async function setPersistedAccountRunHistory(records) {
      const normalizedHistory = normalizeAccountRunHistory(records);
      await chrome.storage.local.set({
        [ACCOUNT_RUN_HISTORY_STORAGE_KEY]: normalizedHistory,
      });
      return normalizedHistory;
    }

    function buildAccountRunHistoryRecord(state = {}, status = '', reason = '') {
      const identity = resolveRecordIdentity({
        accountIdentifierType: state.accountIdentifierType,
        accountIdentifier: state.accountIdentifier,
        email: state.email,
        phoneNumber: resolveStatePhoneNumber(state),
      });
      const email = identity.email;
      const phoneNumber = identity.phoneNumber;
      const accountIdentifierType = identity.accountIdentifierType;
      const accountIdentifier = identity.accountIdentifier;
      const password = String(state.password || state.customPassword || '').trim();
      const finalStatus = normalizeFinalStatus(status);

      if (!accountIdentifier || !finalStatus) {
        return null;
      }

      const failureDetail = finalStatus === 'failed' || finalStatus === 'stopped' ? String(reason || '').trim() : '';
      const failedStep = finalStatus === 'failed' || finalStatus === 'stopped'
        ? extractRecordStep(status, failureDetail)
        : null;
      const source = Boolean(state.autoRunning) ? 'auto' : 'manual';
      const autoRunContext = source === 'auto' ? buildAutoRunContextFromState(state) : null;
      const retryCount = source === 'auto' ? getRetryCountFromState(state) : 0;
      const finishedAt = new Date().toISOString();

      return {
        recordId: buildRecordId(accountIdentifier, accountIdentifierType),
        accountIdentifierType,
        accountIdentifier,
        email,
        phoneNumber,
        password,
        finalStatus,
        finishedAt,
        retryCount,
        failureLabel: buildFailureLabel(finalStatus, failedStep, failureDetail),
        failureDetail,
        failedStep: Number.isInteger(failedStep) && failedStep > 0 ? failedStep : null,
        source,
        autoRunContext,
        plusModeEnabled: Boolean(state.plusModeEnabled),
        contributionMode: Boolean(state.contributionMode),
      };
    }

    function upsertAccountRunHistoryRecord(history, record) {
      const normalizedHistory = normalizeAccountRunHistory(history);
      if (!record) {
        return normalizedHistory;
      }

      const recordId = String(record.recordId || '').trim();
      const emailKey = String(record.email || '').trim().toLowerCase();
      const phoneKey = normalizePhoneRecordKey(record.phoneNumber);
      const identifierKey = buildRecordId(
        record.accountIdentifier || record.email || record.phoneNumber,
        record.accountIdentifierType || (phoneKey && !emailKey ? 'phone' : 'email')
      );
      const nextHistory = normalizedHistory.filter((item) => {
        const itemRecordId = String(item.recordId || '').trim();
        const itemEmailKey = String(item.email || '').trim().toLowerCase();
        const itemPhoneKey = normalizePhoneRecordKey(item.phoneNumber);
        const itemIdentifierKey = buildRecordId(
          item.accountIdentifier || item.email || item.phoneNumber,
          item.accountIdentifierType || (itemPhoneKey && !itemEmailKey ? 'phone' : 'email')
        );
        return itemRecordId !== recordId
          && itemIdentifierKey !== identifierKey
          && (!emailKey || itemEmailKey !== emailKey)
          && (!phoneKey || itemPhoneKey !== phoneKey);
      });

      nextHistory.unshift(record);
      return normalizeAccountRunHistory(nextHistory);
    }

    function deleteAccountRunHistoryEntries(history, recordIds = []) {
      const normalizedHistory = normalizeAccountRunHistory(history);
      const normalizedIds = Array.isArray(recordIds)
        ? recordIds
          .map((value) => String(value || '').trim().toLowerCase())
          .filter(Boolean)
        : [];

      if (!normalizedIds.length) {
        return {
          deletedCount: 0,
          nextHistory: normalizedHistory,
        };
      }

      const selectedIds = new Set(normalizedIds);
      const nextHistory = normalizedHistory.filter((record) => !selectedIds.has(buildRecordId(
        record.recordId || record.accountIdentifier || record.email || record.phoneNumber,
        String(record.recordId || '').startsWith('phone:') || String(record.accountIdentifierType || '').trim().toLowerCase() === 'phone'
          ? 'phone'
          : 'email'
      )));

      return {
        deletedCount: normalizedHistory.length - nextHistory.length,
        nextHistory: normalizeAccountRunHistory(nextHistory),
      };
    }

    async function appendAccountRunHistoryRecord(status, stateOverride = null, reason = '') {
      const state = stateOverride || await getState();
      const record = buildAccountRunHistoryRecord(state, status, reason);
      if (!record) {
        return null;
      }

      const history = await getPersistedAccountRunHistory();
      const nextHistory = upsertAccountRunHistoryRecord(history, record);
      await setPersistedAccountRunHistory(nextHistory);
      return record;
    }

    function summarizeAccountRunHistory(records = []) {
      return normalizeAccountRunHistory(records).reduce((summary, record) => {
        summary.total += 1;
        if (record.finalStatus === 'success') {
          summary.success += 1;
        } else if (record.finalStatus === 'failed') {
          summary.failed += 1;
        } else if (record.finalStatus === 'stopped') {
          summary.stopped += 1;
        }
        summary.retryTotal += normalizeRetryCount(record.retryCount);
        return summary;
      }, {
        total: 0,
        success: 0,
        failed: 0,
        stopped: 0,
        retryTotal: 0,
      });
    }

    function buildAccountRunHistorySnapshotPayload(records = []) {
      const normalizedHistory = normalizeAccountRunHistory(records);
      return {
        generatedAt: new Date().toISOString(),
        summary: summarizeAccountRunHistory(normalizedHistory),
        records: normalizedHistory,
      };
    }

    function shouldSyncAccountRunHistorySnapshot(state = {}) {
      if (Boolean(state.contributionMode)) {
        return false;
      }

      const helperBaseUrl = normalizeAccountRunHistoryHelperBaseUrl(state.accountRunHistoryHelperBaseUrl);
      return Boolean(helperBaseUrl);
    }

    function shouldAppendAccountRunTextFile(state = {}) {
      return shouldSyncAccountRunHistorySnapshot(state);
    }

    async function syncAccountRunHistorySnapshot(records, stateOverride = null) {
      const state = stateOverride || await getState();
      if (!shouldSyncAccountRunHistorySnapshot(state)) {
        return '';
      }

      const helperBaseUrl = normalizeAccountRunHistoryHelperBaseUrl(state.accountRunHistoryHelperBaseUrl);
      let response;
      try {
        response = await fetch(buildLocalHelperEndpoint(helperBaseUrl, '/sync-account-run-records'), {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            Accept: 'application/json',
          },
          body: JSON.stringify(buildAccountRunHistorySnapshotPayload(records)),
        });
      } catch (err) {
        return '';
      }

      let payload = null;
      try {
        payload = await response.json();
      } catch (err) {
        throw new Error(`账号记录快照同步失败：本地 helper 返回了无法解析的响应（${getErrorMessage(err)}）`);
      }

      if (!response.ok || payload?.ok === false) {
        throw new Error(`账号记录快照同步失败：${payload?.error || `HTTP ${response.status}`}`);
      }

      return payload?.filePath || '';
    }

    async function appendAccountRunRecord(status, stateOverride = null, reason = '') {
      const state = stateOverride || await getState();
      const record = await appendAccountRunHistoryRecord(status, state, reason);
      if (!record) {
        return null;
      }

      try {
        const history = await getPersistedAccountRunHistory();
        const filePath = await syncAccountRunHistorySnapshot(history, state);
        if (filePath) {
          await addLog(`账号记录快照已同步到本地：${filePath}`, 'info');
        }
      } catch (err) {
        await addLog(getErrorMessage(err), 'warn');
      }

      return record;
    }

    async function clearAccountRunHistory(stateOverride = null) {
      const state = stateOverride || await getState();
      const history = await getPersistedAccountRunHistory();
      await setPersistedAccountRunHistory([]);

      try {
        const filePath = await syncAccountRunHistorySnapshot([], state);
        if (filePath) {
          await addLog(`账号记录快照已同步到本地：${filePath}`, 'info');
        }
      } catch (err) {
        await addLog(getErrorMessage(err), 'warn');
      }

      return {
        clearedCount: history.length,
      };
    }

    async function deleteAccountRunHistoryRecords(recordIds = [], stateOverride = null) {
      const state = stateOverride || await getState();
      const history = await getPersistedAccountRunHistory();
      const { deletedCount, nextHistory } = deleteAccountRunHistoryEntries(history, recordIds);

      if (!deletedCount) {
        return {
          deletedCount: 0,
          remainingCount: history.length,
        };
      }

      await setPersistedAccountRunHistory(nextHistory);

      try {
        const filePath = await syncAccountRunHistorySnapshot(nextHistory, state);
        if (filePath) {
          await addLog(`账号记录快照已同步到本地：${filePath}`, 'info');
        }
      } catch (err) {
        await addLog(getErrorMessage(err), 'warn');
      }

      return {
        deletedCount,
        remainingCount: nextHistory.length,
      };
    }

    return {
      appendAccountRunRecord,
      appendAccountRunHistoryRecord,
      buildAccountRunHistoryRecord,
      buildAccountRunHistorySnapshotPayload,
      clearAccountRunHistory,
      deleteAccountRunHistoryRecords,
      getPersistedAccountRunHistory,
      normalizeAccountRunHistory,
      normalizeAccountRunHistoryRecord,
      normalizeFinalStatus,
      setPersistedAccountRunHistory,
      shouldAppendAccountRunTextFile,
      shouldSyncAccountRunHistorySnapshot,
      summarizeAccountRunHistory,
      syncAccountRunHistorySnapshot,
    };
  }

  return {
    createAccountRunHistoryHelpers,
  };
});
