#ifndef HIT_RUNTIME_CONTROLLER_MQH
#define HIT_RUNTIME_CONTROLLER_MQH

//+------------------------------------------------------------------+
//| ティック情報を取得する関数
//+------------------------------------------------------------------+
/**
 * @brief 現在のAsk/Bid/スプレッド情報を取得してTickContextへ格納します。
 *
 * @param ctx 取得したティック情報を格納する構造体参照。
 * @return 取得成功時はtrue、ティック情報を取得できない場合はfalse。
 */
bool GetTickContext(TickContext &ctx)
  {
   MqlTick last_tick;
   if(!SymbolInfoTick(_Symbol, last_tick))
      return false;

   ctx.ask           = last_tick.ask;
   ctx.bid           = last_tick.bid;
   ctx.spread_points = MathRound((ctx.ask - ctx.bid) / Point());
   ctx.spread        = ctx.spread_points * Point();
   ctx.digits        = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);

   return true;
  }

//+------------------------------------------------------------------+
//| H4更新検知とトレンド判定Python起動を処理する関数
//+------------------------------------------------------------------+
/**
 * @brief H4新バーまたは初回起動を検知し、トレンド判定Pythonを起動します。
 *
 * @param state EA全体の状態。トレンド更新開始フラグを更新します。
 *
 * Python処理中はdoneファイルが存在しないため、CSVの上書きと二重起動を抑止します。
 */
void ProcessTrendUpdate(EAState &state)
  {
   int current_bars_H4 = iBars(NULL, PERIOD_H4);
   if(g_pre_bars_H4 == 0)
      g_pre_bars_H4 = current_bars_H4;

   int  bars_H4_change = current_bars_H4 - g_pre_bars_H4;
   bool trend_trigger  = (bars_H4_change > 0 || g_init_trend_pending);

   if(!trend_trigger)
      return;

   if(RecordOHLCAndExecuteBatch_Trend(state))
     {
      g_init_trend_pending = false;
      g_pre_bars_H4        = current_bars_H4;
     }
  }

//+------------------------------------------------------------------+
//| トレンド判定Pythonの完了状態を返す関数
//+------------------------------------------------------------------+
/**
 * @brief H4トレンド判定Pythonの完了状態を確認します。
 *
 * @return `process_done_trend.txt` が存在する場合はtrue、未完了の場合はfalse。
 */
bool IsTrendResultReady()
  {
   return IsProcessResultReady(done_trend_file, running_trend_file, trend_state_file, "trend", g_trend_process);
  }

//+------------------------------------------------------------------+
//| トレンド判定結果をEA状態へ反映する関数
//+------------------------------------------------------------------+
/**
 * @brief 完了済みのH4トレンド判定結果をEA状態へ反映します。
 *
 * @param state EA全体の状態。`trend_state` と最終更新時刻が更新されます。
 */
void RefreshTrendState(EAState &state)
  {
   GetTrendState(state);
  }

//+------------------------------------------------------------------+
//| H1更新検知とエントリー価格生成Python起動を処理する関数
//+------------------------------------------------------------------+
/**
 * @brief H1新バーまたは初回起動を検知し、エントリー価格生成Pythonを起動します。
 *
 * @param state EA全体の状態。ターゲット価格更新開始フラグや判定リトライ状態を更新します。
 *
 * Python処理中はdoneファイルが存在しないため、H1 CSVの上書きと二重起動を抑止します。
 */
void ProcessEntryUpdate(EAState &state)
  {
   int current_bars_H1 = iBars(NULL, PERIOD_H1);
   if(g_pre_bars_H1 == 0)
      g_pre_bars_H1 = current_bars_H1;

   int  bars_H1_change = current_bars_H1 - g_pre_bars_H1;
   bool entry_trigger  = (bars_H1_change > 0 || g_init_entry_pending);

   if(!entry_trigger)
      return;

   if(RecordOHLCAndExecuteBatch_Entry(state))
     {
      g_init_entry_pending = false;
      g_bars_H1_check      = true;
      state.chk_cnt        = 0;
      state.last_chk       = 0;
     g_pre_bars_H1        = current_bars_H1;
     }
  }

//+------------------------------------------------------------------+
//| M15更新検知とエントリータイミング判定トリガーを処理する関数
//+------------------------------------------------------------------+
/**
 * @brief M15新バーを検知し、H1候補価格の発注判定を実行できる状態にします。
 *
 * M15は方向判定を上書きする足ではなく、H4/H1で決めた候補価格を発注する
 * タイミング確認として使います。初回は直近の確定M15足で一度だけ判定可能にします。
 */
void ProcessM15EntryTimingUpdate()
  {
   int current_bars_M15 = iBars(NULL, PERIOD_M15);
   if(current_bars_M15 <= 0)
      return;

   if(g_pre_bars_M15 == 0)
     {
      g_pre_bars_M15 = current_bars_M15;
      g_bars_M15_check = true;
      return;
     }

   int bars_M15_change = current_bars_M15 - g_pre_bars_M15;
   if(bars_M15_change <= 0)
      return;

   g_bars_M15_check = true;
   g_pre_bars_M15 = current_bars_M15;
  }

//+------------------------------------------------------------------+
//| チャートコメント文字列を作成する関数
//+------------------------------------------------------------------+
/**
 * @brief チャート左上に表示するステータスメッセージを組み立てます。
 *
 * @param ctx 現在のAsk/Bid/スプレッド情報。
 * @return Comment()へ渡す表示用文字列。
 */
string BuildStatusMessage(TickContext &ctx)
  {
   string message = StringFormat(
                       " \nAsk: %." + IntegerToString(ctx.digits) + "f"
                       "\nBid: %." + IntegerToString(ctx.digits) + "f"
                       "\nSpread: %." + IntegerToString(ctx.digits) + "f"
                       "\nSpread Points: %.0f"
                       "\n\nLast Trend Update:\n %s"
                        "\n\nMarket State: %d (%s)"
                       "\n\nLast Target Update:\n %s"
                       "\n\nMy Used Count: %d / %d"
                       "\nSplit Zone: %s  N=%d  ZoneID=%s"
                       "\n\n[T1 Buy Stop ] en: %." + IntegerToString(ctx.digits) + "f  tp: %." + IntegerToString(ctx.digits) + "f  sl: %." + IntegerToString(ctx.digits) + "f"
                       "\n[T2 Buy Limit] en: %." + IntegerToString(ctx.digits) + "f  tp: %." + IntegerToString(ctx.digits) + "f  sl: %." + IntegerToString(ctx.digits) + "f"
                       "\n[T3 Sell Stop] en: %." + IntegerToString(ctx.digits) + "f  tp: %." + IntegerToString(ctx.digits) + "f  sl: %." + IntegerToString(ctx.digits) + "f"
                       "\n[T4 SellLimit] en: %." + IntegerToString(ctx.digits) + "f  tp: %." + IntegerToString(ctx.digits) + "f  sl: %." + IntegerToString(ctx.digits) + "f\n",
                       ctx.ask, ctx.bid, ctx.spread, ctx.spread_points,
                       TimeToString(g_ea.last_trend_update, TIME_DATE | TIME_MINUTES),
                        g_ea.trend_state, MarketStateName(g_ea.trend_state),
                       TimeToString(g_ea.last_target_update, TIME_DATE | TIME_MINUTES),
                       CountMyUsed(), EffectivePositionLimit(),
                       (use_split_entry_zone ? "ON" : "OFF"), EffectiveSplitEntryCount(), g_ea.zone_candidate_id,
                       g_ea.en_price[1], g_ea.tp_price[1], g_ea.sl_price[1],
                       g_ea.en_price[2], g_ea.tp_price[2], g_ea.sl_price[2],
                       g_ea.en_price[3], g_ea.tp_price[3], g_ea.sl_price[3],
                       g_ea.en_price[4], g_ea.tp_price[4], g_ea.sl_price[4]
                    );
   return message;
  }

//+------------------------------------------------------------------+
//| チャートコメントを更新する関数
//+------------------------------------------------------------------+
/**
 * @brief チャート上のステータスコメントを更新します。
 *
 * @param ctx 現在のAsk/Bid/スプレッド情報。
 */
void UpdateStatusComment(TickContext &ctx)
  {
   Comment(BuildStatusMessage(ctx));
  }

//+------------------------------------------------------------------+
//| market_stateの表示名を返す関数
//+------------------------------------------------------------------+
/**
 * @brief H4 market_stateの人間可読名を返します。
 *
 * @param market_state Pythonが出力したH4環境分類（0..5、6は技術エラー停止）。
 * @return 表示用ラベル。
 */
string MarketStateName(const int market_state)
  {
   switch(market_state)
     {
      case MARKET_LOW_VOL_RANGE:
         return "LOW_VOL_RANGE";
      case MARKET_HIGH_VOL_RANGE:
         return "HIGH_VOL_RANGE";
      case MARKET_LOW_VOL_UP:
         return "LOW_VOL_UP";
      case MARKET_HIGH_VOL_UP:
         return "HIGH_VOL_UP";
      case MARKET_LOW_VOL_DOWN:
         return "LOW_VOL_DOWN";
      case MARKET_HIGH_VOL_DOWN:
         return "HIGH_VOL_DOWN";
      case MARKET_TECHNICAL_ERROR_STOP:
         return "TECHNICAL_ERROR_STOP";
      default:
         return "UNKNOWN";
     }
  }

//+------------------------------------------------------------------+
//| スプレッドが許容範囲内か判定する関数
//+------------------------------------------------------------------+
/**
 * @brief 現在スプレッドが入力パラメータの許容範囲内か判定します。
 *
 * @param ctx 現在のスプレッド情報。
 * @return 許容範囲内ならtrue、超過している場合はfalse。
 */
bool IsSpreadAllowed(TickContext &ctx)
  {
   return (ctx.spread <= spread_limit * Point());
  }

//+------------------------------------------------------------------+
//| エントリー価格生成Pythonの完了状態を返す関数
//+------------------------------------------------------------------+
/**
 * @brief H1エントリー価格生成Pythonの完了状態を確認します。
 *
 * @return `process_done_entry.txt` が存在する場合はtrue、未完了の場合はfalse。
 */
bool IsEntryResultReady()
  {
   return IsProcessResultReady(done_entry_file, running_entry_file, target_prices_file, "entry", g_entry_process);
  }

//+------------------------------------------------------------------+
//| ターゲット価格をEA状態へ反映する関数
//+------------------------------------------------------------------+
/**
 * @brief 完了済みのH1エントリー価格生成結果をEA状態へ反映します。
 *
 * @param state EA全体の状態。`res_chk` と各注文タイプのen/tp/slが更新されます。
 */
void RefreshTargetPrices(EAState &state)
  {
   GetTargetPrices(state);
  }

//+------------------------------------------------------------------+

#endif
