"""
Auto-generated Optimas-CrewAI pipeline for agent: {{ metadata.get('id', agent_name) }}
Builds an Optimas CompoundAISystem from CrewAI agents via the Optimas adapter.
"""

from __future__ import annotations

from typing import Dict, Any, List

from optimas.arch.system import CompoundAISystem
from optimas.adapt.crewai import create_component_from_crewai

try:
	import crewai
except Exception as e:
	crewai = None


def _require_crewai():
	if crewai is None:
		raise ImportError("CrewAI is required for optimas-crewai pipelines. Install: pip install crewai")


def _build_agent(role: str, goal: str, backstory: str, llm_config: Dict[str, Any]) -> "crewai.Agent":
	"""Create a CrewAI Agent from playbook persona and LLM config."""
	_require_crewai()
	# Prefer CrewAI's LLM wrapper when base_url/api_key provided (LiteLLM under the hood)
	model = llm_config.get("model", "gpt-4o-mini")
	base_url = llm_config.get("base_url")
	api_key = llm_config.get("api_key")
	llm: Any = model
	try:
		from crewai import LLM as CrewLLM  # type: ignore
	except Exception:
		CrewLLM = None  # type: ignore
	if base_url or api_key:
		if CrewLLM is not None:
			# Ensure base_url doesn't have /v1 prefix for Ollama
			if base_url and base_url.endswith("/v1"):
				base_url = base_url[:-3]
			llm = CrewLLM(model=model, base_url=base_url, api_key=api_key)
		else:
			# Fallback for older CrewAI versions that accept a dict
			if base_url and base_url.endswith("/v1"):
				base_url = base_url[:-3]
			llm = {"model": model, "base_url": base_url, "api_key": api_key}
	
	# Enhance backstory with JSON formatting instructions
	enhanced_backstory = f"{backstory}\n\nIMPORTANT: You must respond in valid JSON format. Do not include any text before or after the JSON. Your response should be a valid JSON object with the required fields."
	
	return crewai.Agent(
		role=role or "Assistant",
		goal=goal or "Help users",
		backstory=enhanced_backstory,
		llm=llm,
	)


def build_optimas_system() -> CompoundAISystem:
	components: Dict[str, Any] = {}

{% set tasks = spec.get('tasks', []) %}
{% set persona = spec.get('persona', {}) %}
	llm_cfg = {{ spec.get('language_model', {}) }}
	if isinstance(llm_cfg, dict) and llm_cfg.get("provider") == "ollama":
		# CrewAI with LiteLLM expects provider-qualified model names for some backends
		model_name = llm_cfg.get("model", "")
		if model_name and not model_name.startswith("ollama/"):
			llm_cfg["model"] = f"ollama/{model_name}"
		# Ensure base_url doesn't have /v1 prefix for Ollama
		if llm_cfg.get("base_url") and llm_cfg["base_url"].endswith("/v1"):
			llm_cfg["base_url"] = llm_cfg["base_url"][:-3]
	role = "{{ persona.get('title') or persona.get('name') or metadata.get('name', agent_name) }}"
	goal = "{{ persona.get('job_description') or metadata.get('description') }}"
	backstory = "{{ persona.get('backstory') or '' }}"

{% if not tasks %}
	# Single generic agent
	agent = _build_agent(role, goal, backstory, llm_cfg)
	component = create_component_from_crewai(
		agent,
		input_fields=["query"],
		output_fields=["response"],
	)
	components["default_task"] = component
	final_outputs: List[str] = ["response"]
{% else %}
{% for task in tasks %}
	# One agent per task
	{{ task.get('name','task_' ~ loop.index)|to_snake_case }} = _build_agent(role, goal, backstory, llm_cfg)
	{{ task.get('name','task_' ~ loop.index)|to_snake_case }}_component = create_component_from_crewai(
		{{ task.get('name','task_' ~ loop.index)|to_snake_case }},
		input_fields=[{% for f in task.get('inputs', []) %}"{{ f.get('name')|to_snake_case }}"{% if not loop.last %}, {% endif %}{% endfor %}],
		output_fields=[{% for f in task.get('outputs', []) %}"{{ f.get('name')|to_snake_case }}"{% if not loop.last %}, {% endif %}{% endfor %}],
	)
	components["{{ task.get('name','task_' ~ loop.index)|to_snake_case }}"] = {{ task.get('name','task_' ~ loop.index)|to_snake_case }}_component
{% endfor %}
{% set last_task = tasks[-1] %}
	final_outputs: List[str] = [{% for f in last_task.get('outputs', []) %}"{{ f.get('name')|to_snake_case }}"{% if not loop.last %}, {% endif %}{% endfor %}]
{% endif %}

	def eval_func(**kwargs) -> float:
		for k in final_outputs:
			val = kwargs.get(k)
			if isinstance(val, str) and val.strip():
				return 1.0
			if val not in (None, "", [], {}):
				return 1.0
		return 0.0

	# Configure custom meta-prompt for OPRO optimization to avoid safety filter issues
	system = CompoundAISystem(
		components=components,
		final_output_fields=final_outputs,
		ground_fields=[],
		eval_func=eval_func,
	)
	
	# Set custom meta-prompt for optimization
	if hasattr(system, 'components'):
		for component_name, component in system.components.items():
			if hasattr(component, 'meta_prompt_preamble'):
				component.meta_prompt_preamble = (
					"You are an AI assistant helping to refine instructions for a coding task.\n"
					"We have a list of (instruction, performance) pairs to analyze.\n"
					"Please suggest a refined instruction that may improve performance.\n"
					"This is a safe, educational task focused on code quality and clarity.\n"
				)
	
	return system


def system_engine() -> CompoundAISystem:
	return build_optimas_system()


