Documentation
use once_cell::sync::Lazy;
use regex::Regex;

use super::CmdResult;
use crate::AnyRes as _;
use crate::Result;

/// 使用 once_cell 来避免每次调用都重新编译正则表达式
pub static REGEX_R_LOG: Lazy<Regex> = Lazy::new(|| Regex::new(r"R<(?s:.*?)>R").unwrap());

#[inline]
/// 解析 rlog 字符串
pub fn parse_rlog_str(stdout: String) -> Result<String> {
  if let Some(plog) = parse_rlog(&stdout) {
    let plog = plog?;
    if !plog.status {
      return Err(plog.content.into());
    }
    Ok(plog.content)
  } else {
    Ok(stdout)
  }
}
#[inline]
/// 解析 rlog 字符串
pub fn parse_rlog(stdout: &str) -> Option<Result<CmdResult<serde_json::Value>>> {
  if let Some(cap) = REGEX_R_LOG.find_iter(stdout).last() {
    let json_str = &stdout[cap.start() + 2..cap.end() - 2];
    Some(serde_json::from_str::<CmdResult<serde_json::Value>>(json_str).any())
  } else {
    None
  }
}
#[inline]
/// 解析 rlog 字符串并验证
pub fn parse_and_validate_log(stdout: &str) -> Result<String> {
  match parse_rlog(stdout) {
    Some(Ok(res)) if res.status => Ok(res.content.to_string()),
    Some(Ok(res)) => Err(res.content.into()),
    Some(Err(e)) => Err(e.to_string().into()),
    None => Err(format!("{}...", &crate::share::get_safe_preview(stdout, 200)).into()),
  }
}

/// 异步解析 rlog 字符串并验证
#[cfg(feature = "tokio")]
#[inline]
pub async fn a_parse_and_validate_log(stdout: &str) -> crate::Result<String> {
  use crate::share::get_safe_preview;
  use memchr::memmem::find;

  // 克隆 stdout 以避免生命周期问题
  let stdout_clone = stdout.to_owned();

  // 在线程池中执行搜索和解析
  let result = tokio::task::spawn_blocking(move || {
    if let Some(start_pos) = find(stdout_clone.as_bytes(), b"R<") {
      if let Some(cap) = REGEX_R_LOG.find_at(&stdout_clone, start_pos) {
        let json_str = &stdout_clone[cap.start() + 2..cap.end() - 2];
        // 在同一个闭包内解析 JSON
        match serde_json::from_str::<CmdResult<serde_json::Value>>(json_str) {
          Ok(res) if res.status => Ok(res.content),
          Ok(res) => Err(res.content),
          Err(_) => Err(format!("{}...", &get_safe_preview(stdout_clone, 100))),
        }
      } else {
        Err("Cannot find R<...>R tag".into())
      }
    } else {
      Err("Cannot find start position R<".into())
    }
  })
  .await
  .map_err(|_| "Thread error: a_parse_and_validate_log")??;
  Ok(result)
}