"""
Feature 83: CLI Dashboard
Feature 84: Hot reload
Feature 87: Interactive playground
Feature 90: Dry run mode
Feature 91: Cost estimator
Feature 92: Token counter
Feature 93: Latency profiler
Feature 94: Agent behavior testing
Feature 95: Mock agents
Feature 99: Environment config
Feature 100: Config file support
"""
import os
import time
import json
import yaml
from typing import List, Dict, Any, Optional
from datetime import datetime


# ─── Feature 90: Dry Run Mode ─────────────────────────────────────────────────
class DryRunAgent:
    """
    Feature 90: Test your pipeline without making API calls.
    Returns mock responses.
    """
    def __init__(self, name: str, mock_response: str = None):
        self.name = name
        self.mock_response = mock_response or f"[DRY RUN] Mock response from {name}"
        self.provider_name = "dry_run"
        self.model = "mock"
        self.skills = []
        self.version = "1.0.0"
        self.metadata = {}
        self._message_count = 0

    def complete(self, messages: List[Dict], **kwargs) -> str:
        self._message_count += 1
        return self.mock_response

    def card(self):
        from synapse.core.card import AgentCard
        return AgentCard(name=self.name, provider="dry_run", model="mock")

    def health(self) -> dict:
        return {"name": self.name, "status": "dry_run", "message_count": self._message_count}

    def __repr__(self):
        return f"DryRunAgent(name={self.name!r})"


# ─── Feature 95: Mock Agent ────────────────────────────────────────────────────
class MockAgent(DryRunAgent):
    """
    Feature 95: Mock agents for testing.
    Can return different responses based on input.
    """
    def __init__(self, name: str, responses: Dict[str, str] = None):
        super().__init__(name)
        self.responses = responses or {}

    def complete(self, messages: List[Dict], **kwargs) -> str:
        self._message_count += 1
        if messages:
            last = messages[-1]["content"].lower()
            for key, response in self.responses.items():
                if key.lower() in last:
                    return response
        return f"[MOCK] {self.name} response"


# ─── Feature 91: Cost Estimator ───────────────────────────────────────────────
COST_PER_1K_TOKENS = {
    "groq/llama-3.3-70b-versatile": 0.00059,
    "groq/llama-3.1-8b-instant":    0.00005,
    "openai/gpt-4o":                0.005,
    "openai/gpt-3.5-turbo":         0.0005,
    "anthropic/claude-sonnet-4-20250514": 0.003,
    "gemini/gemini-1.5-flash":      0.000075,
}

def estimate_cost(text: str, provider: str, model: str) -> dict:
    """Feature 91: Estimate cost before running."""
    # Rough token estimate: 1 token ≈ 4 chars
    tokens = len(text) / 4
    key = f"{provider}/{model}"
    cost_per_1k = COST_PER_1K_TOKENS.get(key, 0.001)
    estimated_cost = (tokens / 1000) * cost_per_1k
    return {
        "estimated_tokens": int(tokens),
        "estimated_cost_usd": round(estimated_cost, 6),
        "provider": provider,
        "model": model,
    }


# ─── Feature 92: Token Counter ────────────────────────────────────────────────
def count_tokens(text: str) -> int:
    """Feature 92: Rough token count (1 token ≈ 4 chars)."""
    return max(1, len(text) // 4)


# ─── Feature 93: Latency Profiler ─────────────────────────────────────────────
class Profiler:
    """Feature 93: Measure latency of agent calls."""

    def __init__(self):
        self._records: List[Dict] = []

    def start(self, label: str) -> float:
        return time.time()

    def end(self, label: str, start_time: float):
        elapsed = round(time.time() - start_time, 3)
        self._records.append({
            "label": label,
            "elapsed_seconds": elapsed,
            "timestamp": datetime.utcnow().isoformat(),
        })
        return elapsed

    def report(self) -> str:
        if not self._records:
            return "No profiling data."
        lines = ["=== Synapse Profiler Report ==="]
        for r in self._records:
            lines.append(f"  {r['label']}: {r['elapsed_seconds']}s")
        total = sum(r["elapsed_seconds"] for r in self._records)
        lines.append(f"  TOTAL: {round(total, 3)}s")
        return "\n".join(lines)

    def clear(self):
        self._records = []


# ─── Feature 99: Environment Config ───────────────────────────────────────────
def load_env(path: str = ".env"):
    """Feature 99: Load .env file into environment."""
    if not os.path.exists(path):
        return {}
    loaded = {}
    with open(path, "r") as f:
        for line in f:
            line = line.strip()
            if line and not line.startswith("#") and "=" in line:
                key, value = line.split("=", 1)
                os.environ[key.strip()] = value.strip()
                loaded[key.strip()] = value.strip()
    return loaded


# ─── Feature 100: Config File ─────────────────────────────────────────────────
def load_config(path: str) -> dict:
    """
    Feature 100: Load agent config from YAML or JSON file.

    Example YAML:
        agents:
          - name: researcher
            provider: groq
            model: llama-3.3-70b-versatile
    """
    if not os.path.exists(path):
        raise FileNotFoundError(f"Config file not found: {path}")

    with open(path, "r") as f:
        if path.endswith(".yaml") or path.endswith(".yml"):
            try:
                return yaml.safe_load(f)
            except ImportError:
                raise ImportError("Install PyYAML: pip install pyyaml")
        elif path.endswith(".json"):
            return json.load(f)
        else:
            raise ValueError("Config must be .yaml, .yml, or .json")


def agents_from_config(path: str) -> list:
    """Build agents from a config file."""
    from synapse.core.agent import Agent
    config = load_config(path)
    agents = []
    for agent_cfg in config.get("agents", []):
        agents.append(Agent(**agent_cfg))
    return agents


# ─── Feature 94: Test Framework ───────────────────────────────────────────────
class AgentTest:
    """
    Feature 94: Test agent behavior.
    """

    def __init__(self, agent):
        self.agent = agent
        self._tests: List[Dict] = []
        self._results: List[Dict] = []

    def add_test(self, name: str, input: str, expected_contains: str):
        self._tests.append({
            "name": name,
            "input": input,
            "expected_contains": expected_contains,
        })

    def run_all(self) -> dict:
        passed = 0
        failed = 0
        self._results = []

        for test in self._tests:
            try:
                response = self.agent.complete([{"role": "user", "content": test["input"]}])
                success = test["expected_contains"].lower() in response.lower()
                status = "✅ PASS" if success else "❌ FAIL"
                if success:
                    passed += 1
                else:
                    failed += 1
                self._results.append({
                    "name": test["name"],
                    "status": status,
                    "response_preview": response[:100],
                })
            except Exception as e:
                failed += 1
                self._results.append({
                    "name": test["name"],
                    "status": "❌ ERROR",
                    "error": str(e),
                })

        return {
            "passed": passed,
            "failed": failed,
            "total": len(self._tests),
            "results": self._results,
        }

    def report(self) -> str:
        lines = [f"=== Agent Test Report: {self.agent.name} ==="]
        for r in self._results:
            lines.append(f"  {r['status']} {r['name']}")
            if "error" in r:
                lines.append(f"    Error: {r['error']}")
        return "\n".join(lines)
