# Copyright (c) 2025, JINGROW
# License: MIT. See LICENSE

import jingrow
from jingrow.utils.jinja import render_template


def _get_all_local_ai_agents():
	"""获取所有启用的事件触发 Local Ai Agent，支持按PageType和Module分组缓存返回。
	"""
	data = jingrow.get_list(
		"Local Ai Agent",
		filters=[["enabled", "=", 1], ["trigger_mode", "=", "Event Trigger"]],
		fields=[
			"name",
			"agent_name",
			"trigger_mode",
			"event_type",
			"target_pagetype",
			"target_module",
			"condition",
		],
	)

	agents: dict[str, list[dict]] = {}
	for agent in data:
		tp = (agent or {}).get("target_pagetype")
		tm = (agent or {}).get("target_module")
		if tp:
			agents.setdefault(tp, []).append(agent)
		elif tm:
			key = f"module:{tm}"
			agents.setdefault(key, []).append(agent)
	return agents


def run_agent(pg=None, method=None, event=None, page=None, **kwargs):
	"""本地版 Local Ai Agent 事件驱动机制。
	- 支持按 pagetype 与 module 分组、合并去重
	- condition 支持 Jinja2 表达式
	- 使用 contextvars 上下文标记防止无限循环（支持同步和异步场景）
	"""
	# 兼容多种调用方式
	pg = pg or page
	method = event or method or kwargs.get("event")

	# 【防无限循环】检查上下文标记：如果当前调用来自智能体执行，提取智能体ID
	# 使用 contextvars.ContextVar 上下文标记，支持同步和异步场景，防止循环触发
	hook_source = jingrow.get_hook_source()
	current_agent_id = None
	if hook_source and hook_source.startswith("agent:"):
		current_agent_id = hook_source[6:]

	# 支持的事件
	event_list = [
		"on_update",
		"after_insert",
		"on_submit",
		"on_cancel",
		"on_trash",
		"on_change",
		"before_update_after_submit",
	]
	# 事件快速失败
	if method not in event_list:
		return

	ai_agents = _get_all_local_ai_agents()

	# pagetype 分组
	# 兼容 dict 或对象：统一读取 pagetype
	def _get_pg_field(obj, key):
		if isinstance(obj, dict):
			return obj.get(key)
		return getattr(obj, key, None)

	pg_pagetype = _get_pg_field(pg, "pagetype")
	pg_name = _get_pg_field(pg, "name")

	agents_by_pagetype = ai_agents.get(pg_pagetype, []) or []

	# module 分组（仅在存在 module:* 分组时才解析所属模块）
	agents_by_module = []
	if any(isinstance(k, str) and k.startswith("module:") for k in ai_agents.keys()):
		module_name = None
		try:
			ma = jingrow.get_module_app(pg_pagetype)
			if isinstance(ma, dict) and ma.get("success"):
				module_name = ma.get("module")
		except Exception as _e:
			jingrow.log_error("get_module_app failed", f"pagetype={pg_pagetype}", exc=_e)
			module_name = None
		if module_name:
			key = f"module:{module_name}"
			agents_by_module = ai_agents.get(key, []) or []

	# 合并去重（以 name 为键，保持现有行为）
	merged_agents = list({a.get("name"): a for a in agents_by_pagetype + agents_by_module}.values())

	if not merged_agents:
		return

	# 一次性准备渲染上下文（仅当至少一个 agent 有 condition 时才构建）
	any_has_condition = any((a.get("condition") or "").strip() for a in merged_agents)
	base_ctx = None
	pg_ctx_full = None
	if any_has_condition:
		if isinstance(pg, dict):
			base_ctx = pg
		else:
			base_ctx = pg.as_dict() if hasattr(pg, "as_dict") else getattr(pg, "__dict__", {})
		_pt = (base_ctx or {}).get("pagetype") or (getattr(pg, "pagetype", None))
		_nm = (base_ctx or {}).get("name") or (getattr(pg, "name", None))
		if _pt and _nm:
			res_pg = jingrow.get_pg(str(_pt), str(_nm))
			if isinstance(res_pg, dict):
				pg_ctx_full = res_pg

	for agent in merged_agents:
		if agent.get("event_type") == method:
			agent_name = agent.get("name")
			
			# 【防无限循环】如果当前在智能体执行上下文中，且要触发的智能体与当前执行的智能体相同，则跳过
			if current_agent_id and agent_name == current_agent_id:
				continue  # 跳过同一智能体的触发，防止循环

			trigger = False
			if not agent.get("condition"):
				trigger = True
			else:
				try:
					cond_tpl = str(agent.get("condition") or "").strip()
					# 构建渲染上下文：优先复用已获取的完整记录
					pg_ctx = (base_ctx or {})
					if isinstance(pg_ctx_full, dict):
						pg_ctx = pg_ctx_full
					result = render_template(cond_tpl, {"pg": pg_ctx})
					if str(result).strip().lower() in ("true", "1", "yes"):
						trigger = True
				except Exception as _e:
					jingrow.log_error("Condition render error, skip agent", f"agent={agent.get('name')}", exc=_e)
					trigger = False

			if trigger:
				enqueue_local_ai_agent(pg, agent_name)

def enqueue_local_ai_agent(pg, agent_name):
	"""后台实际入队执行 Local Ai Agent。"""
	try:
		agent = jingrow.get_pg("Local Ai Agent", agent_name)
		if not agent:
			return
		if not agent:
			return

		agent_id = agent.get("name")
		agent_name_value = agent.get("agent_name")

		from .local_ai_agent import create_agent_job

		# 将触发上下文透传为执行参数的一部分（由下游路由读取）
		if isinstance(pg, dict):
			event_inputs = {"pagetype": pg.get("pagetype"), "name": pg.get("name")}
		else:
			event_inputs = {"pagetype": getattr(pg, 'pagetype', None), "name": getattr(pg, 'name', None)} if (hasattr(pg, 'pagetype') and hasattr(pg, 'name')) else {}

		_ = create_agent_job(
			agent_id=str(agent_id),
			agent_name=agent_name_value,
			inputs=event_inputs,
			route="jingrow/agents/execute",
		)
	except Exception as e:
		jingrow.log_error("Local Ai Agent执行失败", f"agent={agent_name}, error={str(e)}")



