"""
CrewAI Client for Router
Handles decision: direct LLM vs CrewAI orchestration
"""
import os
import json
import logging
import httpx
from typing import Dict, Any, Optional, Tuple, List
from pathlib import Path

logger = logging.getLogger(__name__)

CREWAI_URL = os.getenv("CREWAI_URL", "http://dagi-staging-crewai-service:9010")
CREWAI_ENABLED = os.getenv("CREWAI_ENABLED", "true").lower() == "true"
CREWAI_ORCHESTRATORS_ALWAYS = os.getenv("CREWAI_ORCHESTRATORS_ALWAYS", "true").lower() == "true"
TOP_LEVEL_CREWAI_ON_DEMAND = os.getenv("TOP_LEVEL_CREWAI_ON_DEMAND", "true").lower() == "true"
TOP_LEVEL_CREWAI_TEAM_LIMIT_FAST = int(os.getenv("TOP_LEVEL_CREWAI_TEAM_LIMIT_FAST", "3"))
TOP_LEVEL_CREWAI_PROFILE_FAST = os.getenv("TOP_LEVEL_CREWAI_PROFILE_FAST", "")
TOP_LEVEL_CREWAI_PROFILE_COMPLEX = os.getenv("TOP_LEVEL_CREWAI_PROFILE_COMPLEX", "")
HELION_CREWAI_TEAM_LIMIT = int(os.getenv("HELION_CREWAI_TEAM_LIMIT", "3"))
CLAN_CREWAI_PROFILE = os.getenv("CLAN_CREWAI_PROFILE", "zhos_mvp")
CLAN_CREWAI_PROFILE_FAST = os.getenv("CLAN_CREWAI_PROFILE_FAST", "default")
CLAN_CREWAI_PROFILE_COMPLEX = os.getenv("CLAN_CREWAI_PROFILE_COMPLEX", CLAN_CREWAI_PROFILE)
CLAN_CREWAI_TEAM_LIMIT_FAST = int(os.getenv("CLAN_CREWAI_TEAM_LIMIT_FAST", "3"))

CREWAI_AGENTS_PATH = os.getenv("CREWAI_AGENTS_PATH", "/config/crewai_agents.json")
FALLBACK_CREWAI_PATH = "/app/config/crewai_agents.json"

MIN_PROMPT_LENGTH_FOR_CREW = 100
COMPLEXITY_KEYWORDS = [
    "план", "plan", "аналіз", "analysis", "дослідження", "research",
    "порівняй", "compare", "розроби", "develop", "створи стратегію",
    "декомпозиція", "decompose", "крок за кроком", "step by step",
    "детально", "in detail", "комплексний", "comprehensive"
]

_crewai_cache = None


def load_crewai_config():
    global _crewai_cache
    if _crewai_cache is not None:
        return _crewai_cache
    
    for path in [CREWAI_AGENTS_PATH, FALLBACK_CREWAI_PATH]:
        try:
            p = Path(path)
            if p.exists():
                with open(p, "r", encoding="utf-8") as f:
                    data = json.load(f)
                logger.info(f"Loaded CrewAI config from {path}")
                _crewai_cache = data
                return data
        except Exception as e:
            logger.warning(f"Could not load from {path}: {e}")
    return None


def get_agent_crewai_info(agent_id):
    config = load_crewai_config()
    if not config:
        return {"enabled": False, "orchestrator": False, "team": []}
    
    orchestrators = config.get("orchestrators", [])
    teams = config.get("teams", {})
    
    is_orchestrator = any(o.get("id") == agent_id for o in orchestrators)
    team_info = teams.get(agent_id, {})
    team_members = team_info.get("members", [])
    
    return {
        "enabled": is_orchestrator,
        "orchestrator": is_orchestrator,
        "team": team_members
    }


def should_use_crewai(agent_id, prompt, agent_config, metadata=None, force_crewai=False):
    """
    Decide whether to use CrewAI orchestration or direct LLM.
    Returns: (use_crewai: bool, reason: str)
    """
    if not CREWAI_ENABLED:
        return False, "crewai_disabled_globally"
    
    if force_crewai:
        return True, "force_crewai_requested"
    
    crewai_info = get_agent_crewai_info(agent_id)
    
    if not crewai_info.get("enabled", False):
        return False, "agent_crewai_disabled"
    
    if not crewai_info.get("orchestrator", False):
        return False, "agent_not_orchestrator"
    
    team = crewai_info.get("team", [])
    if not team:
        return False, "agent_has_no_team"

    metadata = metadata or {}
    force_detailed = bool(metadata.get("force_detailed"))
    requires_complex = bool(metadata.get("requires_complex_reasoning"))

    # Top-level policy: DeepSeek direct path by default; CrewAI only on-demand.
    # This keeps first-touch replies fast and concise across all top-level agents.
    if crewai_info.get("orchestrator", False) and TOP_LEVEL_CREWAI_ON_DEMAND:
        if force_detailed or requires_complex:
            return True, "orchestrator_complex_or_detailed"
        if len(prompt) >= MIN_PROMPT_LENGTH_FOR_CREW:
            prompt_lower = prompt.lower()
            has_complexity = any(kw in prompt_lower for kw in COMPLEXITY_KEYWORDS)
            if has_complexity:
                return True, "orchestrator_complexity_keywords_detected"
        return False, "orchestrator_direct_llm_first"

    # Architecture mode: top-level orchestrators go through CrewAI API by default.
    if CREWAI_ORCHESTRATORS_ALWAYS:
        return True, "orchestrator_default_crewai"
    
    if len(prompt) < MIN_PROMPT_LENGTH_FOR_CREW:
        return False, "prompt_too_short"
    
    prompt_lower = prompt.lower()
    has_complexity = any(kw in prompt_lower for kw in COMPLEXITY_KEYWORDS)
    
    if has_complexity:
        return True, "complexity_keywords_detected"
    
    return False, "default_direct_llm"


async def call_crewai(agent_id, task, context=None, team=None, profile=None):
    try:
        if not team:
            crewai_info = get_agent_crewai_info(agent_id)
            team = crewai_info.get("team", [])

        effective_context = context or {}
        metadata = (effective_context.get("metadata", {}) or {})
        force_detailed = bool(metadata.get("force_detailed"))
        requires_complex = bool(metadata.get("requires_complex_reasoning"))
        is_orchestrator = bool(get_agent_crewai_info(agent_id).get("orchestrator", False))
        # Helion policy: limit CrewAI participants unless user requested detailed mode.
        if agent_id == "helion" and not force_detailed and HELION_CREWAI_TEAM_LIMIT > 0 and len(team) > HELION_CREWAI_TEAM_LIMIT:
            team = team[:HELION_CREWAI_TEAM_LIMIT]
        if (
            is_orchestrator
            and TOP_LEVEL_CREWAI_ON_DEMAND
            and not force_detailed
            and not requires_complex
            and TOP_LEVEL_CREWAI_TEAM_LIMIT_FAST > 0
            and len(team) > TOP_LEVEL_CREWAI_TEAM_LIMIT_FAST
        ):
            team = team[:TOP_LEVEL_CREWAI_TEAM_LIMIT_FAST]
        
        async with httpx.AsyncClient(timeout=600.0) as client:
            effective_profile = profile or (effective_context.get("metadata", {}) or {}).get("crewai_profile")
            if not effective_profile and agent_id == "clan":
                effective_profile = (
                    CLAN_CREWAI_PROFILE_COMPLEX
                    if (force_detailed or requires_complex)
                    else CLAN_CREWAI_PROFILE_FAST
                )
            if not effective_profile and is_orchestrator and TOP_LEVEL_CREWAI_ON_DEMAND:
                if force_detailed or requires_complex:
                    effective_profile = TOP_LEVEL_CREWAI_PROFILE_COMPLEX or None
                else:
                    effective_profile = TOP_LEVEL_CREWAI_PROFILE_FAST or None
            if (
                agent_id == "clan"
                and effective_profile == CLAN_CREWAI_PROFILE_FAST
                and not force_detailed
                and CLAN_CREWAI_TEAM_LIMIT_FAST > 0
                and len(team) > CLAN_CREWAI_TEAM_LIMIT_FAST
            ):
                team = team[:CLAN_CREWAI_TEAM_LIMIT_FAST]

            payload = {
                "task": task,
                "orchestrator_id": agent_id,
                "context": effective_context,
            }
            if effective_profile:
                payload["profile"] = effective_profile
            if team:
                payload["team"] = [
                    m.get("role", str(m)) if isinstance(m, dict) else m 
                    for m in team
                ]
            
            logger.info(f"CrewAI call: agent={agent_id}, team={len(team)} members")
            
            response = await client.post(f"{CREWAI_URL}/crew/run", json=payload)
            
            if response.status_code == 200:
                data = response.json()
                success = data.get("success")
                logger.info(f"CrewAI response: success={success}")
                return data
            else:
                logger.error(f"CrewAI error: {response.status_code}")
                return {"success": False, "result": None, "agents_used": [], "error": f"HTTP {response.status_code}"}
    except Exception as e:
        logger.error(f"CrewAI exception: {e}")
        return {"success": False, "result": None, "agents_used": [], "error": str(e)}


async def get_crewai_health():
    try:
        async with httpx.AsyncClient(timeout=5.0) as client:
            response = await client.get(f"{CREWAI_URL}/health")
            return response.json()
    except Exception as e:
        return {"status": "error", "error": str(e)}
