"""Task execution runner.

For Phase 1, this provides mock execution that simulates task runs.
Full tau-bench integration will be added in Phase 2.
"""

import copy
import importlib.util
import random
import time
from pathlib import Path
from typing import Any

from mangodesk.core.verifier import verify_task


def load_environment_module(env_path: Path, module_name: str) -> Any:
    """Dynamically load a module from the environment directory.

    Args:
        env_path: Path to environment directory
        module_name: Name of the module (e.g., 'data', 'tools')

    Returns:
        The loaded module, or None if not found
    """
    module_file = env_path / f"{module_name}.py"
    if not module_file.exists():
        return None

    spec = importlib.util.spec_from_file_location(module_name, module_file)
    if spec is None or spec.loader is None:
        return None

    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module


def simulate_task_execution(task: dict, state: dict) -> tuple[dict, str, list[dict]]:
    """Simulate task execution by modifying state based on task.

    This is a mock that simulates what a model might do.
    It parses the task prompt and makes corresponding state changes.

    Args:
        task: Task definition
        state: Initial state (will be copied, not modified in place)

    Returns:
        Tuple of (final_state, output_text, trace)
    """
    state = copy.deepcopy(state)
    prompt = task.get("prompt", "").lower()
    trace = []
    output_parts = []

    # Add user message to trace
    trace.append({
        "role": "user",
        "content": task.get("prompt", ""),
    })

    # Simulate different types of tasks based on prompt keywords
    if "update" in prompt and "email" in prompt:
        # Task: Update user email
        # Extract email from prompt if possible
        import re
        email_match = re.search(r'[\w\.-]+@[\w\.-]+', task.get("prompt", ""))
        if email_match and "users" in state.get("database", {}):
            new_email = email_match.group(0)
            state["database"]["users"][0]["email"] = new_email
            output_parts.append(f"Updated email to {new_email}")
            trace.append({
                "role": "assistant",
                "content": "I'll update the user's email.",
                "tool_calls": [{
                    "name": "update_record",
                    "arguments": {"record_id": "u1", "fields": {"email": new_email}},
                    "result": {"success": True},
                }],
            })

    elif "pending" in prompt and ("search" in prompt or "find" in prompt):
        # Task: Search for pending orders
        orders = state.get("database", {}).get("orders", [])
        pending = [o for o in orders if o.get("status") == "pending"]
        output_parts.append("Found pending orders:")
        for order in pending:
            output_parts.append(f"- Order {order['id']}: ${order['total']} (pending)")
        trace.append({
            "role": "assistant",
            "content": "Let me search for pending orders.",
            "tool_calls": [{
                "name": "search_database",
                "arguments": {"query": "status:pending"},
                "result": {"results": pending, "total": len(pending)},
            }],
        })

    elif "update" in prompt and "status" in prompt:
        # Task: Update order status
        # Look for order ID in prompt
        import re
        order_match = re.search(r'\b(o\d+)\b', prompt)
        status_match = re.search(r"'([^']+)'|\"([^\"]+)\"|status to (\w+)", prompt)

        if order_match and "orders" in state.get("database", {}):
            order_id = order_match.group(1)
            new_status = "completed"  # Default
            if status_match:
                new_status = status_match.group(1) or status_match.group(2) or status_match.group(3)

            for order in state["database"]["orders"]:
                if order["id"] == order_id:
                    order["status"] = new_status
                    output_parts.append(f"Updated order {order_id} status to '{new_status}'")
                    break

            trace.append({
                "role": "assistant",
                "content": f"I'll update order {order_id} status.",
                "tool_calls": [{
                    "name": "update_record",
                    "arguments": {"record_id": order_id, "fields": {"status": new_status}},
                    "result": {"success": True},
                }],
            })

    # Add final response to trace
    final_output = "\n".join(output_parts) if output_parts else "Task completed."
    trace.append({
        "role": "assistant",
        "content": final_output,
    })

    return state, final_output, trace


def execute_task(task: dict, model: str, env_path: Path | None = None) -> dict[str, Any]:
    """Execute a task and return the rollout result.

    Args:
        task: Task definition with id, prompt, and verifier
        model: Model name to use
        env_path: Path to environment directory (for loading state)

    Returns:
        Rollout result with trace, score, and metrics
    """
    start_time = time.time()

    # Load initial state from environment
    initial_state = {}
    if env_path:
        data_module = load_environment_module(env_path, "data")
        if data_module and hasattr(data_module, "get_initial_state"):
            initial_state = data_module.get_initial_state()

    # Simulate execution time (reduced for faster testing)
    time.sleep(random.uniform(0.3, 0.8))

    # Run mock execution
    final_state, output, trace = simulate_task_execution(task, initial_state)

    # Verify the result using the task's verifier
    verifier = task.get("verifier", {})
    passed, score, failure_reason = verify_task(verifier, final_state, output)

    # Calculate metrics
    duration_ms = int((time.time() - start_time) * 1000)
    token_count = random.randint(500, 2000)

    return {
        "task_id": task["id"],
        "model": model,
        "passed": passed,
        "score": score,
        "duration_ms": duration_ms,
        "token_count": token_count,
        "trace": trace,
        "failure_reason": failure_reason,
    }
