/**
 * Канал осознанного внимания: осознание стимула после ориентировочного рефлекса.
 *
 * stimuls_consciousness(context) — вызывается из ОР. context может быть числом (actual_stimul_ID)
 * или объектом с полной детализацией: actual_stimul_ID, branchId, novelty, significance,
 * samplesCount, pathArr, well, emotionId, activityID, isResponseStimulus.
 * Новизна условий (ОР) передаётся для анализа и будущей оценки приемлемости запуска автоматизма.
 */
(function (global) {
  'use strict';

  // ========== Оптимизация «тишины мысли» (порог прерывания текущего мышления) ==========
  /**
   * Коэффициент порога внимания: эффективная значимость нового стимула должна быть
   * ≥ (значимость главного цикла × этот коэффициент). Больше — труднее прервать, «тише» мысль.
   * Пример: 1.5 = нужно на 50% выше значимости главного процесса.
   */
  var INTERRUPT_THRESHOLD_ATTENTION_RATIO = 1.5;

  /**
   * При несовпадении темы/ситуации инфокартины с темой/ситуацией главного цикла (при создании)
   * значимость конкурирующего стимула для сравнения умножается на этот множитель (< 1 — сложнее переключить).
   * К стимулам из связной цепочки кадров ЭП с реакциями множитель и понижение при ImportantProblem не применяются.
   */
  var INTERRUPT_THEME_MISMATCH_COMPETITOR_FACTOR = 0.5;

  // Стек фоновых контекстов: при прерывании более значимым стимулом контекст текущего главного цикла
  // сохраняется сюда; диспетчер при завершении главного поднимает следующий из стека (promoteFromBackgroundStack).
  /** Очередь прерываний: стек ID циклов, ставших фоновыми при прерывании (LIFO — последний прерванный возвращается первым). */
  if (!Array.isArray(global.ConsciousnessBackgroundStack)) {
    global.ConsciousnessBackgroundStack = [];
  }
  var MAX_INTERRUPTED_STACK = 10;

  /**
   * Осознание стимула (вызывается из ОР).
   * Осознание стимула (вызывается из ОР).
   *
   * Первый уровень осознания:
   * 1) Берётся семантическая значимость стимула в текущих условиях (well, emotionId, activityID).
   *    Если meanImportance < 0, выполняется поиск по ЭП в более общих условиях (родительский узел дерева)
   *    для того же стимула. Если найден кадр с положительным effect, из его actionImageId берётся «позитивное»
   *    действие, для текущей ветки создаётся/обновляется автоматизм и это действие выполняется.
   *    Функция завершается.
   * 2) Если шаг 1 не сработал, проверяется штатный автоматизм текущей ветки.
   *    Если usefulness не отрицательная (>= 0 или ещё не накоплена, count == 0), его действие выполняется.
   *    Если usefulness < 0, первый уровень осознания не принимает решение (заготовка для второго уровня).
   *
   * При запуске любого автоматизма вызывается removeDelayedReflexesForBranch(branchId) и выставляется флаг
   * automatismRanForBranchIds[branchId], чтобы по этой ветке не запускался генетический рефлекс
   * из processGeneticReflexes после истечения блокировки ОР.
   *
   * @param {number|Object} context — ID образа (FinalImageId) или объект контекста ОР с branchId, novelty,
   *    orientationReflexWinner (если true — конкуренция ОР уже отдала победу этому стимулу; порог прерывания ФО не применяется).
   */
  function stimuls_consciousness(context) {
    var actualId = 0;      // FinalImageId стимула (0 — начальный цикл без стимула)
    var branchId = 0;      // текущий терминальный узел дерева
    var well = 0;
    var emotionId = 0;
    var activityID = 0;    // FinalImageId для условий (как в дереве)
    var callImportance = 0; // значимость данного вызова ФО (для конкуренции потоков осмысления)

    if (typeof context === 'number') {
      if (context <= 0) return;
      actualId = context;
      branchId = (typeof global.PerceptionTree_getActiveTerminalNodeId === 'function')
        ? global.PerceptionTree_getActiveTerminalNodeId() : 0;
      well = global.BadNormWell || 0;
      if (typeof global.Emotions_getOrCreateEmotionId === 'function' && Array.isArray(global.BasicContextsActived)) {
        emotionId = global.Emotions_getOrCreateEmotionId(global.BasicContextsActived) || 0;
      }
      activityID = actualId;
    } else if (context && typeof context === 'object') {
      actualId = context.actual_stimul_ID;
      branchId = context.branchId != null
        ? context.branchId
        : ((typeof global.PerceptionTree_getActiveTerminalNodeId === 'function')
          ? global.PerceptionTree_getActiveTerminalNodeId() : 0);
      well = context.well != null ? context.well : (global.BadNormWell || 0);
      emotionId = context.emotionId != null ? context.emotionId : 0;
      activityID = context.activityID != null ? context.activityID : (actualId || 0);
      if (typeof context.significance === 'number') {
        callImportance = Math.abs(context.significance);
      }
    }
    var orWinner = !!(context && typeof context === 'object' && context.orientationReflexWinner === true);
    var vitalEmergency = !!(context && typeof context === 'object' && context.vitalEmergency === true);
    if (typeof branchId !== 'number' && (branchId == null || branchId === undefined)) return;

    // --- Конкуренция потоков осмысления: см. INTERRUPT_THRESHOLD_ATTENTION_RATIO, INTERRUPT_THEME_MISMATCH_COMPETITOR_FACTOR вверху файла ---
    var info = (typeof global.Info_initIfNeeded === 'function')
      ? global.Info_initIfNeeded()
      : (global.InfoPicture || null);
    var currentThinkingImportance = info && typeof info.thinkingImportance === 'number'
      ? info.thinkingImportance
      : 0;

    var mainForInterrupt = typeof global.Consciousness_getMainCycle === 'function'
      ? global.Consciousness_getMainCycle() : null;
    /** Тишина мыслей и понижение «слабых» стимулов относительно главного — только пока главный цикл ещё не expired. */
    var mainBlocksThoughtSilence = !!(mainForInterrupt && !mainForInterrupt.expired);
    var isMainExpired = !!(mainForInterrupt && mainForInterrupt.expired);
    var importantProblem = !!(info && info.ImportantProblem);
    var themeSituationMismatch = false;
    if (mainBlocksThoughtSilence && mainForInterrupt && info) {
      var mt = mainForInterrupt.createdThemeId != null ? mainForInterrupt.createdThemeId : 0;
      var ms = mainForInterrupt.createdSituationId != null ? mainForInterrupt.createdSituationId : 0;
      var it = info.themeId != null ? info.themeId : 0;
      var is = info.situationId != null ? info.situationId : 0;
      themeSituationMismatch = (mt !== it || ms !== is);
    }

    var episodicChainPriority = typeof global.EpisodicMemory_isStimulusEpisodicChainPriority === 'function' &&
      global.EpisodicMemory_isStimulusEpisodicChainPriority(actualId);

    var effectiveCallImportance = callImportance;
    if (mainBlocksThoughtSilence && !episodicChainPriority) {
      effectiveCallImportance *= (themeSituationMismatch ? INTERRUPT_THEME_MISMATCH_COMPETITOR_FACTOR : 1);
      if (importantProblem) {
        effectiveCallImportance *= 0.5;
      }
    }
    var ratio = (mainBlocksThoughtSilence && !episodicChainPriority)
      ? INTERRUPT_THRESHOLD_ATTENTION_RATIO
      : 1.0;
    var requiredMin = currentThinkingImportance * ratio;

    var skipImportanceCheck = !mainBlocksThoughtSilence || episodicChainPriority || orWinner || vitalEmergency;
    if (!skipImportanceCheck && currentThinkingImportance > 0 && effectiveCallImportance < requiredMin) {
      if (typeof global.show_alert === 'function') {
        var stimIdWeak = (context && typeof context.actual_stimul_ID === 'number') ? context.actual_stimul_ID : actualId;
        global.show_alert(
          'Стимул FinalImageId=' + String(stimIdWeak) +
          ': значимость стимула ' + String(callImportance) +
          (themeSituationMismatch
            ? ', для сравнения ×0.5 (тема/ситуация ≠ главного цикла) → эффективно ' + String(effectiveCallImportance)
            : '') +
          '<br>Нужно ≥ ' + String(Math.round(requiredMin * 100) / 100) +
          ' (' + String(ratio * 100) + '% от значимости главного цикла ' + String(currentThinkingImportance) + (isMainExpired ? ', главный expired' : '') + ').',
          1500
        );
      }
      return;
    }

    // Прерывание: текущий главный переводим в фоновый (isMainCycle=false), его ID пушим в стек очереди прерываний.
    // Цикл остаётся в реестре, диспетчер даёт ему шаг раз в 5 пульсов. После завершения нового главного
    // возвращаем в главные прерванные по порядку (pop из стека).
    var createCycle = global.Consciousness_createCycle;
    var setMainCycle = global.Consciousness_setMainCycle;
    var getMainCycle = global.Consciousness_getMainCycle;
    if (typeof getMainCycle === 'function') {
      var main = getMainCycle();
      if (main && Array.isArray(global.ConsciousnessBackgroundStack) && global.ConsciousnessBackgroundStack.length < MAX_INTERRUPTED_STACK) {
        global.ConsciousnessBackgroundStack.push(main.id);
      }
    }

    var runContext = {
      actual_stimul_ID: actualId,
      branchId: branchId,
      well: well,
      emotionId: emotionId,
      activityID: activityID,
      significance: context && typeof context.significance === 'number' ? context.significance : callImportance
    };
    if (typeof createCycle !== 'function') return;
    var cycle = createCycle(runContext);
    if (!cycle) return;
    runContext.processId = cycle.id;
    if (typeof setMainCycle === 'function') setMainCycle(cycle.id);
    global.ConsciousnessCurrentProcessId = cycle.id;

    // Новый актуальный стимул передаёт свою значимость главному циклу (в ходе процесса weight может меняться).
    if (info && callImportance) {
      info.thinkingImportance = callImportance;
      info.thinkingProcessId = cycle.id;
      if (typeof global.Info_updateView === 'function') global.Info_updateView();
    }
    if (cycle && typeof callImportance === 'number' && callImportance > 0) {
      cycle.weight = callImportance;
    }

    if (typeof global.Consciousness_cycleAppendLog === 'function' && cycle && cycle.isMainCycle) {
      global.Consciousness_cycleAppendLog(cycle, 'ФО: новый главный цикл #' + String(cycle.id) + ', FinalImageId=' + String(actualId) + ', ветка=' + String(branchId) + '.', typeof global.cpuls === 'number' ? global.cpuls : 0);
    }

    if (typeof global.Consciousness_runElementary === 'function') {
      global.Consciousness_runElementary(cycle);
    }
  }

  /**
   * Элементарный проход осознания (уровни 1 и 2): один вызов по контексту цикла.
   * Вызывается при создании цикла и при подъёме из стека фоновых. По завершении либо
   * cycle.status = 'finished' (автоматизм запущен), либо cycle.step = 1 и передача на уровень 2.
   * @param {Object} cycle - объект цикла из реестра (cycle.context, cycle.id)
   */
  function runElementary(cycle) {
    if (!cycle || !cycle.context) return;
    if (cycle.status !== 'running') return;
    var ctx = cycle.context;
    var actualId = ctx.actual_stimul_ID != null ? ctx.actual_stimul_ID : 0;
    var branchId = ctx.branchId != null ? ctx.branchId : 0;
    var well = ctx.well != null ? ctx.well : (global.BadNormWell || 0);
    var emotionId = ctx.emotionId != null ? ctx.emotionId : 0;
    var activityID = ctx.activityID != null ? ctx.activityID : actualId;

    global.EpisodicMemory_pendingFeedbackAutomatizmId = 0;
    cycle.waitingFeedbackAutomatizmId = 0;

    var automatismStarted = false;

/////////////////////////////////// ПЕРВЫЙ уровень глубины осознания //////////////////
// Поиск «позитивного» действия по семантике и ЭП, затем штатный автоматизм ветки.
    if (actualId && branchId) {
      if (typeof global.Consciousness_cycleAppendLog === 'function' && cycle && cycle.isMainCycle) {
        global.Consciousness_cycleAppendLog(cycle, 'Уровень 1: анализ семантики/ЭП и запуск автоматизма (если возможно).', typeof global.cpuls === 'number' ? global.cpuls : 0);
      }
      var semanticObj = (typeof global.getSemanticObjectFast === 'function' && well && (emotionId || activityID))
        ? global.getSemanticObjectFast(well, emotionId, activityID)
        : null;
      if (semanticObj && typeof semanticObj.meanImportance === 'number' && semanticObj.meanImportance < 0) {
        var parentNodeId = 0;
        if (typeof global.PerceptionTree_getNode === 'function') {
          var node = global.PerceptionTree_getNode(branchId);
          if (node && typeof node.parentId === 'number') parentNodeId = node.parentId;
        }
        if (parentNodeId && Array.isArray(global.Episodes)) {
          var bestActionImageId = null;
          var bestEffect = 0;
          for (var i = 0; i < global.Episodes.length; i++) {
            var f = global.Episodes[i];
            if (!f || f.perceptionNodeId !== parentNodeId || f.stimulusImageId !== actualId) continue;
            if (typeof f.effect !== 'number' || f.effect <= 0 || f.actionImageId == null) continue;
            if (bestActionImageId === null || f.effect > bestEffect) {
              bestActionImageId = f.actionImageId;
              bestEffect = f.effect;
            }
          }
          if (bestActionImageId != null) {
            if (typeof global.Consciousness_cycleAppendLog === 'function' && cycle && cycle.isMainCycle) {
              global.Consciousness_cycleAppendLog(cycle, 'Найдена позитивная реакция по ЭП: запускаю действие (ОД) ' + String(bestActionImageId) + '.', typeof global.cpuls === 'number' ? global.cpuls : 0);
            }
            var automatizmIdEp = 0;
            if (typeof global.Automatizms_createAutomatizm === 'function') {
              automatizmIdEp = global.Automatizms_createAutomatizm(branchId, bestActionImageId);
              if (automatizmIdEp && typeof global.Automatizms_setDefaultAutomatizm === 'function') {
                global.Automatizms_setDefaultAutomatizm(automatizmIdEp);
              }
            }
            if (typeof global.info_automatismWithEpisodeFeedbackAndExpireCycle === 'function') {
              automatismStarted = global.info_automatismWithEpisodeFeedbackAndExpireCycle(
                cycle,
                branchId,
                bestActionImageId,
                automatizmIdEp,
                0,
                'Найдена позитивная реакция по ЭП: запускаю действие (ОД) ' + String(bestActionImageId) + '.'
              );
            }
          }
        }
      }

      if (!automatismStarted) {
        var defaultAutomatizm = (typeof global.Automatizms_getDefaultAutomatizmForBranch === 'function')
          ? global.Automatizms_getDefaultAutomatizmForBranch(branchId) : null;
        if (defaultAutomatizm && defaultAutomatizm.actionsImageId) {
          var u = typeof defaultAutomatizm.usefulness === 'number' ? defaultAutomatizm.usefulness : 0;
          var c = typeof defaultAutomatizm.count === 'number' ? defaultAutomatizm.count : 0;
          if (!(c > 0 && u < 0)) {
            if (typeof global.Consciousness_cycleAppendLog === 'function' && cycle && cycle.isMainCycle) {
              global.Consciousness_cycleAppendLog(cycle, 'Штатный автоматизм ветки: запускаю действие (ОД) ' + String(defaultAutomatizm.actionsImageId) + '.', typeof global.cpuls === 'number' ? global.cpuls : 0);
            }
            if (typeof global.info_automatismWithEpisodeFeedbackAndExpireCycle === 'function') {
              automatismStarted = global.info_automatismWithEpisodeFeedbackAndExpireCycle(
                cycle,
                branchId,
                defaultAutomatizm.actionsImageId,
                defaultAutomatizm.id,
                0,
                'Штатный автоматизм ветки: запускаю действие (ОД) ' + String(defaultAutomatizm.actionsImageId) + '.'
              );
            }
          }
        }
      }
    }

/////////////////////////////////// ВТОРОЙ уровень глубины осознания //////////////////
// Если автоматизм не запущен на 1-м уровне, фиксируем проблему и передаём её во 2-й уровень.
    /*
     * Фаза ожидания обратной связи по автоматизму (запуск автоматизма с ур.1).
     *
     * Здесь возникает событие ожидания: цикл остаётся running, step = 1, awaitingAutomatismEpisodeFeedback = true,
     * пока по ЭП не придёт результат (ответ оператора в периоде ожидания и т.д.). Эпизодическая память и
     * инфокартина связывают этот цикл с автоматизмом (EpisodicMemory_waitingAutomatismCycleId, activeWaitingAnswer).
     *
     * Запуск автоматизма и ожидание: info_automatismWithEpisodeFeedbackAndExpireCycle — цикл сразу expired и не главный;
     * ответ оператора тянет conscience_level_2 из episodic_memory.closeLastFrame. Финализация фазы —
     * conscience_level_2_finalizeAutomatismAnswerCycle (awaiting снимается, isOperatorAnswerReceived обнуляется и т.д.).
     */
    if (automatismStarted) {
      return;
    }

    global.unsolved_problem = actualId;
    if (typeof global.Info_setProblemFromUnsolved === 'function') global.Info_setProblemFromUnsolved(actualId);
    // Сомнение в штатном автоматизме: 1-й уровень не смог запустить автоматизм, переходим на 2-й уровень.
    if (typeof global.InfoDet_updateDoubtInDefaultAutomatism === 'function') {
      global.InfoDet_updateDoubtInDefaultAutomatism(true);
    }
    if (typeof global.Consciousness_cycleAppendLog === 'function' && cycle && cycle.isMainCycle) {
      global.Consciousness_cycleAppendLog(cycle, 'Автоматизм не запущен. Уровень 2: постановка нерешённой проблемы и выбор цели.', typeof global.cpuls === 'number' ? global.cpuls : 0);
    }
    if (typeof global.conscience_level_2 === 'function') {
      global.conscience_level_2({
        actualId: actualId,
        branchId: branchId,
        well: well,
        emotionId: emotionId,
        activityID: activityID,
        sourceContext: cycle.context,
        sourceCycle: cycle
      });
    }
    cycle.step = 1;
  }

  /**
   * Локальная сигнатура прогресса пассивного фантазма для фонового цикла (без записи в глобальную инфокартину).
   */
  function passiveFantasyLocalSig(cycle) {
    var plot = cycle && cycle.fantazmingPlot;
    var ch = plot && plot.chain ? plot.chain.length : 0;
    var last = plot && plot.lastGeneratedActionId != null ? plot.lastGeneratedActionId : 0;
    var fa = cycle && Array.isArray(cycle.fantasizmArr) ? cycle.fantasizmArr.length : 0;
    return String(ch) + '|' + String(last) + '|' + String(fa);
  }

  /**
   * Один шаг цикла мышления (для диспетчера). Вызывается по каждому пульсу для главного цикла.
   * step === 0 уже обработан элементарным проходом при создании/подъёме; здесь — шаги мышления.
   *
   * Если у цикла thinkingMode === 'passive', уровни 3–4 не выполняются: только info_fantasizming.
   * У главного — антистагнация по сигнатуре инфокартины; у фонового — по локальному сюжету (fantazmingPlot / fantasizmArr).
   *
   * @param {Object} cycle
   */
  function runOneStep(cycle) {
    if (!cycle || cycle.status !== 'running') return;
    if (cycle.step === 0) return;
    if (cycle.step >= 1) {
      // Цикл после автоматизма ждёт кадр ЭП; когда оператор ответил стимулом, эпизодика закрывает кадр
      // и выставляет automatismOperatorAnswerReceived. Инфокартина: isOperatorAnswerReceived.
      // Пока automatismAnswerLevel2Done ложно, на каждом пульсе можно попасть сюда — фактическая
      // обработка один раз (пайплайн + finalize) внутри conscience_level_2 по флагам цикла/инфокартины.
      if (cycle.awaitingAutomatismEpisodeFeedback && cycle.automatismOperatorAnswerReceived && !cycle.automatismAnswerLevel2Done) {
        var inf = global.InfoPicture;
        // Двойная проверка: флаг цикла (от эпизодики) + флаг инфокартины (ответ оператора в UI/детекторах).
        if (inf && inf.isOperatorAnswerReceived && typeof global.conscience_level_2 === 'function') {
          if (typeof global.Consciousness_cycleAppendLog === 'function' && cycle.isMainCycle) {
            global.Consciousness_cycleAppendLog(cycle, 'ФО runOneStep: ответ оператора получен — вход в ур.2 (пайплайн).', typeof global.cpuls === 'number' ? global.cpuls : 0);
          }
          var cx = cycle.context || {};
          global.conscience_level_2({
            sourceCycle: cycle,
            actualId: cx.actual_stimul_ID,
            branchId: cx.branchId,
            well: cx.well,
            emotionId: cx.emotionId,
            activityID: cx.activityID,
            // Только блок isOperatorAnswerReceived в начале conscience_level_2; цели/ImportantProblem здесь не трогаем.
            _operatorAnswerCycleOnly: true
          });
        }
        // Всегда return на этой ветке для «ожидающего» цикла: не спускаться в уровень 3+ за тот же тик.
        return;
      }

      // Ожидание ответа по кадру ЭП без ещё пришедшего ответа — ур. 3–4 не крутим (иначе повторный поиск правил каждый пульс).
      if (cycle.awaitingAutomatismEpisodeFeedback && !cycle.automatismOperatorAnswerReceived) {
        return;
      }

      // --- Пассивный режим мышления цикла (thinkingMode === 'passive') — антагонист целевого пайплайна ур.3–4.
      // Режим хранится на цикле, не в InfoPicture. Главный цикл пишет «Сюжет фантазма» в инфокартину; фоновый — только
      // fantasizmArr + fantazmingPlot на объекте цикла (см. info_fantasizming).
      if (cycle.thinkingMode === 'passive') {
        var sigBefore;
        var sigAfter;
        if (cycle.isMainCycle) {
          var sigGet = global.Consciousness_getInfoPictureSignature;
          sigBefore = typeof sigGet === 'function' ? sigGet() : '';
          if ((cycle.passiveFantasyNoChangeStreak || 0) >= 3 && sigBefore === cycle.passiveFantasyLastSig) {
            return;
          }
          if (typeof global.info_fantasizming === 'function') {
            global.info_fantasizming(cycle);
          }
          sigAfter = typeof sigGet === 'function' ? sigGet() : '';
        } else {
          sigBefore = passiveFantasyLocalSig(cycle);
          if ((cycle.passiveFantasyNoChangeStreak || 0) >= 3 && sigBefore === cycle.passiveFantasyLastSig) {
            return;
          }
          if (typeof global.info_fantasizming === 'function') {
            global.info_fantasizming(cycle);
          }
          sigAfter = passiveFantasyLocalSig(cycle);
        }
        if (sigBefore === sigAfter) {
          cycle.passiveFantasyNoChangeStreak = (cycle.passiveFantasyNoChangeStreak || 0) + 1;
        } else {
          cycle.passiveFantasyNoChangeStreak = 0;
        }
        cycle.passiveFantasyLastSig = sigAfter;
        return;
      }

/////////////////////////////////// ТРЕТИЙ уровень глубины осознания //////////////////
// Условия тика и отработка — conscience_level_3.js (conscience_level_3_runFromChannel).
      if (typeof global.conscience_level_3_runFromChannel === 'function') {
        global.conscience_level_3_runFromChannel(cycle);
      }

/////////////////////////////////// ЧЕТВЕРТЫЙ уровень глубины осознания //////////////////
// Заготовка тика — conscience_level_4.js (conscience_level_4_runFromChannel).
      if (typeof global.conscience_level_4_runFromChannel === 'function') {
        global.conscience_level_4_runFromChannel(cycle);
      }
    }
  }

  global.Consciousness_runElementary = runElementary;
  global.Consciousness_runOneStep = runOneStep;

  /**
   * Фоновая версия функции осознания.
   * Запускается, когда новый, более значимый стимул прерывает текущий основной цикл.
   * В этой заготовке фоновая функция ничего не меняет в инфокартине и автоматизмах,
   * а только фиксирует факт вызова. Реальная логика будет добавлена отдельно.
   */
  function stimuls_consciousness_background(context) {
    if (!context) return;
    if (global.console && typeof global.console.log === 'function') {
      global.console.log('stimuls_consciousness_background invoked', context);
    }
  }

  global.stimuls_consciousness = stimuls_consciousness;
  global.stimuls_consciousness_background = stimuls_consciousness_background;
})(window);
