"""
Core Agent Framework for ALwrity Autonomous Marketing System
Built on txtai's native Agent framework (smolagents)
"""

import asyncio
import json
import logging
from datetime import datetime
from typing import Dict, List, Any, Optional, Callable
from dataclasses import dataclass, asdict
from abc import ABC, abstractmethod

# txtai imports for native agent framework
try:
    from txtai.pipeline import Agent, LLM
    TXTAI_AVAILABLE = True
except ImportError:
    try:
        from txtai import Agent, LLM
        TXTAI_AVAILABLE = True
    except ImportError:
        TXTAI_AVAILABLE = False
        Agent = None
        LLM = None
        logging.warning("txtai not available")

# Optional MLflow integration
try:
    import mlflow
    MLFLOW_AVAILABLE = True
except ImportError:
    MLFLOW_AVAILABLE = False

from utils.logger_utils import get_service_logger
from services.database import get_session_for_user
from services.intelligence.monitoring.semantic_dashboard import RealTimeSemanticMonitor
from services.intelligence.agents.safety_framework import get_safety_framework
from services.agent_activity_service import AgentActivityService

logger = get_service_logger(__name__)

@dataclass
class AgentAction:
    """Represents an action taken by an agent"""
    action_id: str
    agent_type: str
    action_type: str
    target_resource: str
    parameters: Dict[str, Any]
    expected_outcome: str
    risk_level: float  # 0.0 to 1.0
    requires_approval: bool = False
    created_at: str = None
    
    def __post_init__(self):
        if self.created_at is None:
            self.created_at = datetime.utcnow().isoformat()

@dataclass
class MarketSignal:
    """Represents a market change or opportunity"""
    signal_id: str
    signal_type: str  # 'competitor', 'serp', 'social', 'industry', 'performance'
    source: str
    description: str
    impact_score: float  # 0.0 to 1.0
    urgency_level: str  # 'low', 'medium', 'high', 'critical'
    confidence_score: float  # 0.0 to 1.0
    related_topics: List[str]
    suggested_actions: List[str]
    detected_at: str = None
    expires_at: str = None
    
    def __post_init__(self):
        if self.detected_at is None:
            self.detected_at = datetime.utcnow().isoformat()
        if self.expires_at is None:
            # Default expiration: 7 days for most signals
            expires = datetime.utcnow().timestamp() + (7 * 24 * 60 * 60)
            self.expires_at = datetime.fromtimestamp(expires).isoformat()

@dataclass
class AgentPerformance:
    """Performance metrics for an agent"""
    agent_id: str
    total_actions: int
    successful_actions: int
    failed_actions: int
    average_response_time: float
    success_rate: float
    last_action_at: str
    efficiency_score: float  # 0.0 to 1.0

class BaseALwrityAgent(ABC):
    """Base class for all ALwrity marketing agents"""

    _prompt_context_cache: Dict[str, Dict[str, Any]] = {}
    _profile_cache: Dict[str, Dict[str, Any]] = {}
    
    def __init__(self, user_id: str, agent_type: str, model_name: str = "Qwen/Qwen3-4B-Instruct-2507", llm: Any = None, enable_tracing: bool = True):
        self.user_id = user_id
        self.agent_type = agent_type
        self.model_name = model_name
        self.agent_id = f"{agent_type}_{user_id}_{datetime.utcnow().strftime('%Y%m%d%H%M%S')}"
        self.enable_tracing = enable_tracing
        self.performance = AgentPerformance(
            agent_id=self.agent_id,
            total_actions=0,
            successful_actions=0,
            failed_actions=0,
            average_response_time=0.0,
            success_rate=0.0,
            last_action_at=None,
            efficiency_score=0.0
        )
        
        # Initialize txtai agent if available
        self.txtai_agent = None
        self.llm = llm  # Ensure llm is set if provided, regardless of txtai availability

        self.agent_key = self._resolve_agent_key(agent_type)
        self._agent_profile = self._load_agent_profile_overrides()
        self._prompt_context = self._load_prompt_context()
        
        if TXTAI_AVAILABLE:
            try:
                if not self.llm:
                    # Allow txtai to auto-detect the correct task for the model
                    # But force language-generation (txtai mapping for text-generation) for known models
                    task_hint = "language-generation" if any(x in model_name for x in ["Qwen", "Instruct", "GPT", "Llama"]) else None
                    self.llm = LLM(path=model_name, task=task_hint) if task_hint else LLM(path=model_name)
                    
                self.txtai_agent = self._create_txtai_agent()
                logger.info(f"Initialized txtai agent for {agent_type} - {self.agent_id}")
            except Exception as e:
                logger.error(f"Failed to initialize txtai agent for {agent_type}: {e}")
                self.txtai_agent = self._create_fallback_agent()
        else:
            self.txtai_agent = self._create_fallback_agent()

        # Initialize safety framework
        self.safety_framework = get_safety_framework(user_id)

    def _resolve_agent_key(self, agent_type: str) -> str:
        value = str(agent_type or "").strip()
        if value.lower() == "strategyorchestrator".lower():
            return "strategy_orchestrator"
        return value

    def _load_agent_profile_overrides(self) -> Dict[str, Any]:
        cache_key = f"{self.user_id}:{self.agent_key}"
        cached = BaseALwrityAgent._profile_cache.get(cache_key)
        if cached is not None:
            return cached

        profile_data: Dict[str, Any] = {}
        db = None
        try:
            db = get_session_for_user(self.user_id)
            if not db:
                BaseALwrityAgent._profile_cache[cache_key] = profile_data
                return profile_data
            from models.agent_activity_models import AgentProfile

            profile = (
                db.query(AgentProfile)
                .filter(AgentProfile.user_id == self.user_id, AgentProfile.agent_key == self.agent_key)
                .first()
            )
            if not profile:
                profile = (
                    db.query(AgentProfile)
                    .filter(AgentProfile.user_id == self.user_id, AgentProfile.agent_type == self.agent_type)
                    .first()
                )
            if profile:
                profile_data = {
                    "display_name": profile.display_name,
                    "enabled": bool(profile.enabled) if profile.enabled is not None else None,
                    "schedule": profile.schedule,
                    "notification_prefs": profile.notification_prefs,
                    "tone": profile.tone,
                    "system_prompt": profile.system_prompt,
                    "task_prompt_template": profile.task_prompt_template,
                    "reporting_prefs": profile.reporting_prefs,
                }
        except Exception:
            profile_data = {}
        finally:
            try:
                if db:
                    db.close()
            except Exception:
                pass

        BaseALwrityAgent._profile_cache[cache_key] = profile_data
        return profile_data

    def _load_prompt_context(self) -> Dict[str, Any]:
        cached = BaseALwrityAgent._prompt_context_cache.get(self.user_id)
        if cached is not None:
            return cached

        context: Dict[str, Any] = {"website_name": "Your", "website_url": "", "user_id": self.user_id}
        db = None
        try:
            db = get_session_for_user(self.user_id)
            if not db:
                BaseALwrityAgent._prompt_context_cache[self.user_id] = context
                return context

            from api.content_planning.services.content_strategy.onboarding.data_integration import (
                OnboardingDataIntegrationService,
            )

            svc = OnboardingDataIntegrationService()
            integrated = svc.get_integrated_data_sync(self.user_id, db) or {}
            website_analysis = integrated.get("website_analysis") or {}
            canonical = integrated.get("canonical_profile") or {}

            website_url = (
                website_analysis.get("website_url")
                or website_analysis.get("website")
                or canonical.get("website_url")
                or canonical.get("website")
                or ""
            )
            domain = website_analysis.get("domain") or canonical.get("domain") or ""
            website_name = ""
            if domain:
                website_name = str(domain).split(".")[0].strip()
            if not website_name and website_url:
                try:
                    from urllib.parse import urlparse
                    host = urlparse(str(website_url)).hostname or ""
                    host = host.replace("www.", "")
                    website_name = host.split(".")[0].strip() or host
                except Exception:
                    website_name = ""

            context = {
                "user_id": self.user_id,
                "website_url": str(website_url or ""),
                "website_name": str(website_name or "Your"),
            }

            writing_style = canonical.get("writing_style") or {}
            if isinstance(writing_style, dict):
                if writing_style.get("tone"):
                    context["writing_tone"] = writing_style.get("tone")
                if writing_style.get("voice"):
                    context["writing_voice"] = writing_style.get("voice")
        except Exception:
            pass
        finally:
            try:
                if db:
                    db.close()
            except Exception:
                pass

        BaseALwrityAgent._prompt_context_cache[self.user_id] = context
        return context

    def _render_prompt_template(self, text: str) -> str:
        value = str(text or "")
        ctx = self._prompt_context or {}
        for k, v in ctx.items():
            placeholder = "{" + str(k) + "}"
            if placeholder in value:
                value = value.replace(placeholder, str(v))
        return value

    def get_effective_system_prompt(self, default_prompt: str) -> str:
        override = (self._agent_profile or {}).get("system_prompt")
        selected = override if (override is not None and str(override).strip()) else default_prompt
        return self._render_prompt_template(selected)

    def get_effective_task_prompt_template(self, default_template: str = "") -> str:
        override = (self._agent_profile or {}).get("task_prompt_template")
        selected = override if (override is not None and str(override).strip()) else default_template
        return self._render_prompt_template(selected)

    def build_task_prompt(self, instruction: str, task_context: Optional[Dict[str, Any]] = None, default_template: str = "") -> str:
        template = self.get_effective_task_prompt_template(default_template or "")
        context_json = json.dumps(task_context or {}, ensure_ascii=False)
        if template and template.strip():
            return f"{template}\n\nInstruction: {instruction}\nContext: {context_json}"
        return f"Task: {instruction}\nContext: {context_json}\n\nPlease execute this task using your specialized tools and provide a detailed report."
    
    @abstractmethod
    def _create_txtai_agent(self) -> Agent:
        """Create txtai agent with specific tools and configuration"""
        pass
    
    def _create_fallback_agent(self):
        """Fallback agent for development/testing when txtai is not available"""
        class FallbackAgent:
            def __init__(self, agent_type: str):
                self.agent_type = agent_type
                self.available = False
            
            async def run(self, prompt: str, **kwargs) -> str:
                return f"[FALLBACK] {self.agent_type} agent would process: {prompt[:100]}..."
        
        return FallbackAgent(self.agent_type)
    
    async def run(self, prompt: str) -> str:
        """Run the agent with a prompt directly (compatibility method)"""
        db = None
        activity = None
        run_record = None
        try:
            try:
                db = get_session_for_user(self.user_id)
                if db:
                    activity = AgentActivityService(db, self.user_id)
                    run_record = activity.start_run(agent_type=self.agent_type, prompt=prompt)
                    activity.log_event(
                        event_type="plan",
                        severity="info",
                        message=(prompt[:2000] if prompt else None),
                        payload={"kind": "prompt"},
                        run_id=run_record.id,
                        agent_type=self.agent_type,
                    )
            except Exception:
                activity = None
                run_record = None

            if self.txtai_agent:
                # Check if txtai_agent has run method (e.g. if it's my fallback agent)
                if hasattr(self.txtai_agent, 'run'):
                    if asyncio.iscoroutinefunction(self.txtai_agent.run):
                        result = await self.txtai_agent.run(prompt)
                    else:
                        result = self.txtai_agent.run(prompt)
                else:
                    loop = asyncio.get_event_loop()
                    result = await loop.run_in_executor(None, self.txtai_agent, prompt)
            
            if not self.txtai_agent:
                result = "Agent not initialized"

            if activity and run_record:
                activity.log_event(
                    event_type="final_summary",
                    severity="info",
                    message=(str(result)[:2000] if result is not None else None),
                    payload={"kind": "result"},
                    run_id=run_record.id,
                    agent_type=self.agent_type,
                )
                activity.finish_run(run_record.id, success=True, result_summary=(str(result)[:4000] if result is not None else None))
            return result
        except Exception as e:
            logger.error(f"Error running agent {self.agent_id}: {e}")
            if activity and run_record:
                try:
                    activity.log_event(
                        event_type="error",
                        severity="error",
                        message=str(e)[:2000],
                        payload={"kind": "exception"},
                        run_id=run_record.id,
                        agent_type=self.agent_type,
                    )
                    activity.finish_run(run_record.id, success=False, error_message=str(e)[:4000])
                    activity.create_alert(
                        alert_type="agent_run_failed",
                        title=f"{self.agent_type} failed",
                        message=str(e)[:2000],
                        severity="error",
                        payload={"agent_id": self.agent_id, "agent_type": self.agent_type},
                        dedupe_key=None,
                    )
                except Exception:
                    pass
            return f"Error: {str(e)}"
        finally:
            try:
                if db:
                    db.close()
            except Exception:
                pass

    async def execute_action(self, action: AgentAction) -> Dict[str, Any]:
        """Execute an agent action with performance tracking, safety validation, and rollback support"""
        start_time = datetime.utcnow()
        checkpoint_id = None
        db = None
        activity = None
        run_record = None
        
        try:
            logger.info(f"Agent {self.agent_id} executing action: {action.action_type}")

            try:
                db = get_session_for_user(self.user_id)
                if db:
                    activity = AgentActivityService(db, self.user_id)
                    run_record = activity.start_run(
                        agent_type=self.agent_type,
                        prompt=f"{action.action_type} -> {action.target_resource}",
                    )
                    activity.log_event(
                        event_type="plan",
                        severity="info",
                        message=f"{action.action_type} -> {action.target_resource}",
                        payload={"action": asdict(action)},
                        run_id=run_record.id,
                        agent_type=self.agent_type,
                    )
            except Exception:
                activity = None
                run_record = None
            
            # 1. Validate action safety
            if not await self._validate_action_safety(action):
                if activity and run_record:
                    activity.log_event(
                        event_type="decision",
                        severity="warning",
                        message="Action failed safety validation",
                        payload={"action_id": action.action_id, "action_type": action.action_type},
                        run_id=run_record.id,
                        agent_type=self.agent_type,
                    )
                    activity.finish_run(run_record.id, success=False, error_message="Action failed safety validation")
                return {
                    "success": False,
                    "error": "Action failed safety validation",
                    "action_id": action.action_id,
                    "agent_id": self.agent_id
                }

            if action.requires_approval:
                approval_id = None
                if activity:
                    req = activity.create_approval_request(
                        action_id=action.action_id,
                        action_type=action.action_type,
                        target_resource=action.target_resource,
                        risk_level=action.risk_level,
                        payload=asdict(action),
                        agent_type=self.agent_type,
                        run_id=run_record.id if run_record else None,
                        expires_at=None,
                    )
                    approval_id = req.id
                    activity.create_alert(
                        alert_type="approval_required",
                        title=f"Approval required: {action.action_type}",
                        message=f"Agent requested approval for {action.action_type} on {action.target_resource}",
                        severity="warning" if action.risk_level < 0.8 else "error",
                        payload={"approval_id": req.id, "action_id": action.action_id, "action_type": action.action_type},
                        cta_path="/approvals",
                        dedupe_key=f"approval:{req.id}",
                    )
                    if run_record:
                        activity.log_event(
                            event_type="decision",
                            severity="info",
                            message="Action requires approval",
                            payload={"approval_id": req.id, "action_id": action.action_id},
                            run_id=run_record.id,
                            agent_type=self.agent_type,
                        )
                        activity.finish_run(run_record.id, success=False, error_message="Pending approval")
                return {
                    "success": False,
                    "requires_approval": True,
                    "approval_request_id": approval_id,
                    "action_id": action.action_id,
                    "agent_id": self.agent_id,
                }
            
            # 2. Create rollback checkpoint
            try:
                # Capture current system state
                current_state = await self._capture_system_state(action)
                checkpoint_id = await self.safety_framework["rollback_manager"].create_checkpoint(
                    asdict(action), current_state
                )
                if activity and run_record:
                    activity.log_event(
                        event_type="progress",
                        severity="info",
                        message="Rollback checkpoint created",
                        payload={"checkpoint_id": checkpoint_id},
                        run_id=run_record.id,
                        agent_type=self.agent_type,
                    )
            except Exception as e:
                logger.warning(f"Failed to create checkpoint: {e}")
                if activity and run_record:
                    activity.log_event(
                        event_type="warning",
                        severity="warning",
                        message=str(e)[:2000],
                        payload={"checkpoint": "failed"},
                        run_id=run_record.id,
                        agent_type=self.agent_type,
                    )
                # Continue execution even if checkpoint fails? Maybe not for critical actions.
                # For now, we log and proceed.

            # 3. Execute action (with MLflow tracing if enabled)
            if self.txtai_agent and self.txtai_agent.available:
                if self.enable_tracing and MLFLOW_AVAILABLE:
                    with mlflow.start_run(run_name=f"{self.agent_type}_{action.action_type}"):
                        mlflow.log_param("agent_id", self.agent_id)
                        mlflow.log_param("action_type", action.action_type)
                        mlflow.log_dict(action.parameters, "parameters.json")
                        
                        result = await self._execute_with_txtai(action)
                        
                        mlflow.log_text(str(result), "result.txt")
                else:
                    result = await self._execute_with_txtai(action)
            else:
                result = await self._execute_fallback(action)
            
            # 4. Update performance metrics
            end_time = datetime.utcnow()
            response_time = (end_time - start_time).total_seconds()
            await self._update_performance_metrics(True, response_time)
            
            logger.info(f"Agent {self.agent_id} action completed successfully: {action.action_id}")

            if activity and run_record:
                activity.log_event(
                    event_type="final_summary",
                    severity="info",
                    message=str(result)[:2000] if result is not None else None,
                    payload={"action_id": action.action_id},
                    run_id=run_record.id,
                    agent_type=self.agent_type,
                )
                activity.finish_run(run_record.id, success=True, result_summary=str(result)[:4000] if result is not None else None)
            
            return {
                "success": True,
                "result": result,
                "action_id": action.action_id,
                "agent_id": self.agent_id,
                "execution_time": response_time,
                "timestamp": end_time.isoformat()
            }
            
        except Exception as e:
            logger.error(f"Agent {self.agent_id} action failed: {action.action_id} - {e}")
            
            # 5. Handle failure and rollback if needed
            if checkpoint_id:
                logger.info(f"Initiating rollback to checkpoint {checkpoint_id}")
                await self.safety_framework["rollback_manager"].rollback_to_checkpoint(checkpoint_id)
            
            # Track failure in SIF if available
            if hasattr(self, 'sif_service') and self.sif_service:
                try:
                    # Avoid circular import by checking attribute existence
                    # Pass action dict as context
                    await self.sif_service.track_agent_failure(
                        agent_id=self.agent_id,
                        error=e,
                        context=asdict(action)
                    )
                except Exception as tracking_err:
                    logger.warning(f"Failed to track agent failure in SIF: {tracking_err}")
            
            # Update performance metrics
            end_time = datetime.utcnow()
            response_time = (end_time - start_time).total_seconds()
            await self._update_performance_metrics(False, response_time)
            
            if self.enable_tracing and MLFLOW_AVAILABLE:
                 mlflow.log_metric("success", 0)
                 mlflow.log_param("error", str(e))

            if activity and run_record:
                try:
                    activity.log_event(
                        event_type="error",
                        severity="error",
                        message=str(e)[:2000],
                        payload={"action_id": action.action_id, "checkpoint_id": checkpoint_id},
                        run_id=run_record.id,
                        agent_type=self.agent_type,
                    )
                    activity.finish_run(run_record.id, success=False, error_message=str(e)[:4000])
                    activity.create_alert(
                        alert_type="agent_action_failed",
                        title=f"{self.agent_type}: {action.action_type} failed",
                        message=str(e)[:2000],
                        severity="error",
                        payload={"agent_id": self.agent_id, "action_id": action.action_id, "action_type": action.action_type},
                    )
                except Exception:
                    pass

            return {
                "success": False,
                "error": str(e),
                "action_id": action.action_id,
                "agent_id": self.agent_id,
                "execution_time": response_time,
                "timestamp": end_time.isoformat(),
                "rollback_initiated": bool(checkpoint_id)
            }
        finally:
            try:
                if db:
                    db.close()
            except Exception:
                pass
    
    async def _capture_system_state(self, action: AgentAction) -> Dict[str, Any]:
        """Capture current system state for rollback purposes"""
        state = {"timestamp": datetime.utcnow().isoformat()}
        
        try:
            # Determine state to capture based on action type
            
            # SEO Optimization (Check first to avoid being caught by generic 'optimize')
            if "seo" in action.action_type:
                 state["seo_state"] = {
                     "target": action.target_resource,
                     "timestamp": datetime.utcnow().isoformat()
                 }
                 if "current_settings" in action.parameters:
                     state["seo_state"]["settings"] = action.parameters["current_settings"]

            # Content Modification
            elif any(kw in action.action_type for kw in ["update", "rewrite", "optimize", "modify", "blog", "article"]):
                if "content_id" in action.parameters:
                    # In a real implementation, fetch from DB using content_id
                    # For now, we capture what we can from parameters or minimal state
                    state["original_content"] = {
                        "id": action.parameters.get("content_id"),
                        "version": "pre_modification"
                    }
                    if "original_content" in action.parameters:
                         state["original_content"]["data"] = action.parameters["original_content"]

        except Exception as e:
            logger.warning(f"Failed to capture detailed system state: {e}")
            
        return state

    async def _execute_with_txtai(self, action: AgentAction) -> str:
        """Execute action using txtai agent"""
        try:
            # Prepare prompt for txtai agent
            prompt = self._prepare_agent_prompt(action)
            
            # Execute with txtai agent via self.run logic
            result = await self.run(prompt)
            
            return result
            
        except Exception as e:
            logger.error(f"txtai agent execution failed: {e}")
            raise e
    
    async def _execute_fallback(self, action: AgentAction) -> str:
        """Execute fallback action when txtai is not available"""
        # Simulate agent processing for development
        logger.info(f"Executing fallback action: {action.action_type}")
        
        # Return simulated result based on action type
        if action.action_type == "analyze_competitor":
            return "Competitor analysis completed (fallback mode)"
        elif action.action_type == "optimize_content":
            return "Content optimization completed (fallback mode)"
        elif action.action_type == "fix_seo_issue":
            return "SEO issue fixed (fallback mode)"
        else:
            return f"Action {action.action_type} completed (fallback mode)"
    
    def _prepare_agent_prompt(self, action: AgentAction) -> str:
        """Prepare prompt for txtai agent"""
        return f"""
        You are the {self.agent_type} agent for ALwrity user {self.user_id}.
        
        Action Details:
        - Type: {action.action_type}
        - Target: {action.target_resource}
        - Parameters: {json.dumps(action.parameters, indent=2)}
        - Expected Outcome: {action.expected_outcome}
        - Risk Level: {action.risk_level}
        
        Please execute this action and provide a detailed response.
        Consider user goals, safety constraints, and potential impacts.
        """
    
    async def _validate_action_safety(self, action: AgentAction) -> bool:
        """Validate action against safety constraints"""
        try:
            # Use SafetyConstraintManager from safety_framework
            validation_result = await self.safety_framework["constraint_manager"].validate_action(asdict(action))
            
            if not validation_result.is_valid:
                logger.warning(f"Safety validation failed for action {action.action_id}: {validation_result.violations}")
                
                # Check if approval is required and handle it
                if validation_result.requires_approval:
                    logger.info(f"Requesting approval for action {action.action_id}")
                    await self.safety_framework["approval_system"].request_approval(asdict(action))
                    return False # Pending approval counts as false for immediate execution
                
                return False
                
            return True
        except Exception as e:
            logger.error(f"Error during safety validation: {e}")
            # Fail safe
            return False
    
    async def _update_performance_metrics(self, success: bool, response_time: float):
        """Update agent performance metrics"""
        self.performance.total_actions += 1
        self.performance.last_action_at = datetime.utcnow().isoformat()
        
        if success:
            self.performance.successful_actions += 1
        else:
            self.performance.failed_actions += 1
        
        # Update average response time
        if self.performance.average_response_time == 0:
            self.performance.average_response_time = response_time
        else:
            self.performance.average_response_time = (
                (self.performance.average_response_time * (self.performance.total_actions - 1) + response_time) 
                / self.performance.total_actions
            )
        
        # Update success rate
        if self.performance.total_actions > 0:
            self.performance.success_rate = (
                self.performance.successful_actions / self.performance.total_actions
            )
        
        # Calculate efficiency score (0.0 to 1.0)
        # Based on success rate and response time
        time_factor = min(1.0, 30.0 / max(self.performance.average_response_time, 1.0))
        self.performance.efficiency_score = (
            self.performance.success_rate * 0.7 + time_factor * 0.3
        )
    
    def get_performance_metrics(self) -> AgentPerformance:
        """Get current performance metrics"""
        return self.performance
    
    async def get_current_status(self) -> Dict[str, Any]:
        """Get current agent status"""
        return {
            "agent_id": self.agent_id,
            "agent_type": self.agent_type,
            "user_id": self.user_id,
            "status": "active" if self.txtai_agent else "fallback",
            "performance": asdict(self.performance),
            "last_updated": datetime.utcnow().isoformat()
        }

class StrategyOrchestratorAgent(BaseALwrityAgent):
    """Central orchestrator agent that coordinates all marketing agents"""
    
    def __init__(self, user_id: str, market_detector: Any = None, performance_monitor: Any = None, llm: Any = None):
        super().__init__(user_id, "StrategyOrchestrator", llm=llm)
        self.market_detector = market_detector
        self.performance_monitor = performance_monitor
        self.sub_agents = {}
        self.active_strategies = []
        
    def set_sub_agents(self, agents: Dict[str, Any]):
        """Set available sub-agents"""
        self.sub_agents = agents
    
    def _create_txtai_agent(self) -> Agent:
        """Create txtai orchestrator agent with coordination tools"""
        if not TXTAI_AVAILABLE:
            return None

        llm = getattr(self.llm, "llm", self.llm)
        return Agent(llm=llm, tools=[], max_iterations=15)
    
    async def _market_signal_detector_tool(self, context: Dict[str, Any]) -> Dict[str, Any]:
        """Tool for detecting market signals"""
        try:
            signals = []
            if self.market_detector:
                signals = await self.market_detector.detect_market_signals()
            
            return {
                "signals_detected": len(signals),
                "latest_signals": [s.dict() for s in signals[-5:]] if signals else [],
                "threat_level": self._assess_threat_level(signals),
                "timestamp": datetime.utcnow().isoformat()
            }
        except Exception as e:
            return {"error": str(e), "signals": []}

    async def _google_trends_fetcher_tool(self, context: Dict[str, Any]) -> Dict[str, Any]:
        try:
            keywords = context.get("keywords") or []
            timeframe = context.get("timeframe") or "today 12-m"
            geo = context.get("geo") or "US"

            if not isinstance(keywords, list):
                keywords = [str(keywords)]
            keywords = [str(k).strip() for k in keywords if str(k).strip()]
            if not keywords:
                return {"error": "keywords is required", "success": False}

            from services.research.trends.google_trends_service import GoogleTrendsService
            from services.intelligence.txtai_service import TxtaiIntelligenceService

            trends = await GoogleTrendsService().analyze_trends(
                keywords=keywords,
                timeframe=timeframe,
                geo=geo,
                user_id=self.user_id,
            )

            run_id = datetime.utcnow().strftime("%Y%m%dT%H%M%SZ")
            latest_id = f"market_trends_latest:{self.user_id}"
            run_doc_id = f"market_trends_run:{self.user_id}:{run_id}"

            summary = (
                f"LATEST Market Trends for {geo} ({timeframe}). Keywords: {', '.join(trends.get('keywords', keywords))}. "
                f"Related queries top: {len((trends.get('related_queries') or {}).get('top', []))}. "
                f"Related topics top: {len((trends.get('related_topics') or {}).get('top', []))}."
            )

            metadata = {
                "type": "market_trends",
                "user_id": self.user_id,
                "run_id": run_id,
                "run_timestamp": trends.get("timestamp") or datetime.utcnow().isoformat(),
                "timeframe": timeframe,
                "geo": geo,
                "keywords": trends.get("keywords", keywords),
                "is_latest": True,
                "full_report": trends,
            }

            intelligence = TxtaiIntelligenceService(self.user_id)
            await intelligence.index_content(
                [
                    (latest_id, summary, metadata),
                    (run_doc_id, summary, {**metadata, "is_latest": False}),
                ]
            )

            return {
                "success": True,
                "run_id": run_id,
                "latest_doc_id": latest_id,
                "run_doc_id": run_doc_id,
                "keywords": trends.get("keywords", keywords),
                "geo": geo,
                "timeframe": timeframe,
                "timestamp": datetime.utcnow().isoformat(),
            }
        except Exception as e:
            return {"success": False, "error": str(e)}
    
    async def _agent_coordinator_tool(self, context: Dict[str, Any]) -> Dict[str, Any]:
        """Tool for coordinating agent actions"""
        return {
            "agents_available": list(self.sub_agents.keys()),
            "coordination_status": "active",
            "last_coordination": datetime.utcnow().isoformat()
        }
    
    async def _performance_analyzer_tool(self, context: Dict[str, Any]) -> Dict[str, Any]:
        """Tool for analyzing performance metrics"""
        try:
            perf_data = {}
            if self.performance_monitor:
                perf_data = self.performance_monitor.get_all_agents_performance()
                
            return {
                "overall_performance": perf_data,
                "agent_efficiency": self.performance.efficiency_score,
                "recommendations": ["Optimize content agent latency", "Increase SEO agent throughput"],
                "timestamp": datetime.utcnow().isoformat()
            }
        except Exception as e:
            return {"error": str(e)}
    
    async def _strategy_synthesizer_tool(self, context: Dict[str, Any]) -> Dict[str, Any]:
        """Tool for synthesizing strategies"""
        return {
            "strategies_active": len(self.active_strategies),
            "synthesis_capability": "ready",
            "unified_strategy": "Focus on high-engagement topics while monitoring competitor X",
            "last_synthesis": datetime.utcnow().isoformat()
        }
    
    async def _delegate_task_tool(self, context: Dict[str, Any]) -> Dict[str, Any]:
        """
        Tool to delegate a specific task to a specialized agent.
        Expected context keys: 'agent_name', 'instruction', 'task_context'
        """
        agent_name = context.get('agent_name')
        instruction = context.get('instruction')
        task_context = context.get('task_context', {})
        
        if not agent_name or not instruction:
            return {"error": "Missing agent_name or instruction"}
            
        agent = self.sub_agents.get(agent_name)
        if not agent:
            return {"error": f"Agent {agent_name} not available. Available: {list(self.sub_agents.keys())}"}
            
        try:
            # Delegate execution to the sub-agent
            logger.info(f"Delegating task to {agent_name}: {instruction}")
            sub_agent_prompt = None
            if hasattr(agent, "build_task_prompt"):
                try:
                    sub_agent_prompt = agent.build_task_prompt(instruction=instruction, task_context=task_context)
                except Exception:
                    sub_agent_prompt = None
            if not sub_agent_prompt:
                sub_agent_prompt = f"Task: {instruction}\nContext: {json.dumps(task_context)}\n\nPlease execute this task using your specialized tools and provide a detailed report."
            
            # Execute the agent
            result = await agent.run(sub_agent_prompt)
            
            return {
                "status": "success",
                "agent": agent_name,
                "result": result,
                "timestamp": datetime.utcnow().isoformat()
            }
        except Exception as e:
            logger.error(f"Delegation to {agent_name} failed: {e}")
            return {"error": str(e)}

    def _assess_threat_level(self, signals: List[Any] = None) -> str:
        """Assess current threat level based on market signals"""
        if not signals:
            return "low"
            
        critical_count = len([s for s in signals if getattr(s, 'urgency_level', 'low') == 'critical'])
        if critical_count > 0:
            return "critical"
            
        high_count = len([s for s in signals if getattr(s, 'urgency_level', 'low') == 'high'])
        if high_count > 2:
            return "high"
            
        return "moderate"

# Global agent service instance (Deprecated, use agent_orchestrator.py)
# This file now focuses on core definitions
