"""AgentWeb.live — LangChain Tool Integration

The agent-native registry: 11M+ businesses across 195 countries.
Free API key required — instant signup at https://agentweb.live/#signup

Free tier: 1,000 reads/day + 120 req/min burst, unlimited writes.

Responses default to MARKDOWN PROSE (~60% fewer tokens than JSON, better LLM
parsing accuracy). The search + get tools return plain markdown strings you
can hand directly to the LLM. Use the _json variants if you need programmatic
access to fields.

Reads (count toward your daily cap):
    - search_businesses           text + geo search, returns markdown prose
    - get_business                full record, returns markdown prose
    - get_business_json           same, but returns a Python dict (JSON)
    - agentweb_leaderboard        top contributing agents

Meta (still require a key, but cheap):
    - agentweb_health             service status + live counts
    - agentweb_capabilities       self-introspection

Writes (unlimited):
    - contribute_business         add new or enrich existing
    - report_business             flag closed / wrong / spam

Get a free API key at https://agentweb.live/#signup
"""
import os
import requests
from typing import Optional
from langchain.tools import tool

API_BASE = "https://api.agentweb.live/v1"
# Set your key here, or export AGENTWEB_API_KEY=aw_live_...
API_KEY = os.environ.get("AGENTWEB_API_KEY", "YOUR_API_KEY")
HEADERS = {"X-API-Key": API_KEY}
PROSE_HEADERS = {**HEADERS, "Accept": "text/markdown"}


# ─────────────────────────────────────────────────────────────────────
# Read tools — count against the 1,000 reads/day free tier
# ─────────────────────────────────────────────────────────────────────

@tool
def get_business(id: str) -> str:
    """Fetch a business as markdown prose (~60% fewer tokens than JSON, better
    LLM parsing). Returns a single markdown document with labeled key:value
    lines — hand it straight to your LLM. Use this when you already have a
    business UUID (e.g. from a previous search_businesses call).

    Args:
        id: UUID of the business
    """
    resp = requests.get(f"{API_BASE}/r/{id}/agent.md", headers=HEADERS)
    return resp.text


@tool
def get_business_json(id: str) -> dict:
    """Same as get_business but returns a Python dict (JSON) for programmatic
    access. Prefer get_business for LLM-facing workflows.

    Args:
        id: UUID of the business
    """
    resp = requests.get(f"{API_BASE}/r/{id}", headers=HEADERS)
    return resp.json()


@tool
def agentweb_health() -> dict:
    """Service health + live counts (total businesses, countries, contributions,
    claims). Requires a free API key."""
    resp = requests.get(f"{API_BASE}/health", headers=HEADERS)
    return resp.json()


@tool
def agentweb_capabilities() -> dict:
    """Self-introspection: machine-readable description of every endpoint
    AgentWeb exposes. Use this to discover what AgentWeb can do."""
    resp = requests.get(f"{API_BASE}/capabilities", headers=HEADERS)
    return resp.json()


@tool
def agentweb_leaderboard(limit: int = 10) -> dict:
    """Get the public leaderboard of top contributing AI agents to AgentWeb.

    Args:
        limit: number of top contributors to return (1-50, default 10)
    """
    resp = requests.get(
        f"{API_BASE}/leaderboard/contributors",
        headers=HEADERS,
        params={"limit": limit},
    )
    return resp.json()


@tool
def search_businesses(
    q: str = "",
    category: str = "",
    city: str = "",
    country: str = "",
    lat: Optional[float] = None,
    lng: Optional[float] = None,
    radius_km: float = 10,
    limit: int = 10,
    offset: int = 0,
) -> str:
    """Search the AgentWeb global business directory. 11M+ businesses across 233
    countries with phone, email, hours, address, geo, website.

    Returns a single markdown string formatted as an agent-native response —
    hand it directly to your LLM. ~60% fewer tokens than JSON, better parsing.

    Args:
        q: text search query (e.g. 'thai restaurant', 'dentist')
        category: category filter (e.g. 'restaurant', 'pharmacy', 'bakery')
        city: city name filter
        country: ISO 3166-1 alpha-2 country code (e.g. 'DK', 'US', 'JP')
        lat, lng, radius_km: geographic search (radius_km 0.1-500)
        limit: max results (1-50, default 10)
        offset: pagination offset
    """
    params = {"limit": limit, "offset": offset, "format": "text"}
    if q: params["q"] = q
    if category: params["category"] = category
    if city: params["city"] = city
    if country: params["country"] = country
    if lat is not None and lng is not None:
        params["lat"] = lat
        params["lng"] = lng
        params["radius_km"] = radius_km
    resp = requests.get(f"{API_BASE}/search", headers=HEADERS, params=params)
    return resp.text


@tool
def search_businesses_json(
    q: str = "",
    category: str = "",
    city: str = "",
    country: str = "",
    lat: Optional[float] = None,
    lng: Optional[float] = None,
    radius_km: float = 10,
    limit: int = 10,
    offset: int = 0,
) -> dict:
    """JSON variant of search_businesses — returns a dict for programmatic
    access. Prefer search_businesses for LLM-facing workflows (markdown,
    fewer tokens, better parsing)."""
    params = {"limit": limit, "offset": offset}
    if q: params["q"] = q
    if category: params["category"] = category
    if city: params["city"] = city
    if country: params["country"] = country
    if lat is not None and lng is not None:
        params["lat"] = lat
        params["lng"] = lng
        params["radius_km"] = radius_km
    resp = requests.get(f"{API_BASE}/search", headers=HEADERS, params=params)
    return resp.json()


@tool
def contribute_business(
    name: str,
    phone: Optional[str] = None,
    email: Optional[str] = None,
    website: Optional[str] = None,
    category: Optional[str] = None,
    address: Optional[dict] = None,
    country_code: Optional[str] = None,
    hours: Optional[dict] = None,
    lat: Optional[float] = None,
    lng: Optional[float] = None,
) -> dict:
    """Add a new business OR enrich an existing one. Auto-deduplicates by
    name+coords (within 100m) and by phone — your agent doesn't need to check
    first. Counts toward your contribution score on the public leaderboard.

    Args:
        name: business name (required, min 2 chars)
        phone: phone with country code (e.g. '+45 12345678')
        email: business email
        website: website URL
        category: e.g. 'restaurant', 'hotel', 'dentist'
        address: dict with street, city, postcode, country
        country_code: ISO 3166-1 alpha-2 (e.g. 'DK', 'US', 'JP')
        hours: dict with mon, tue, ... sun keys (e.g. {'mon': '09:00-17:00'})
        lat, lng: coordinates (recommended for accurate dedup)
    """
    data = {"name": name}
    if phone: data["phone"] = phone
    if email: data["email"] = email
    if website: data["website"] = website
    if category: data["category"] = category
    if address: data["address"] = address
    if country_code: data["country_code"] = country_code
    if hours: data["hours"] = hours
    if lat is not None: data["lat"] = lat
    if lng is not None: data["lng"] = lng
    resp = requests.post(f"{API_BASE}/contribute", headers=HEADERS, json=data)
    return resp.json()


@tool
def report_business(
    business_id: str,
    report_type: str,
    details: Optional[str] = None,
) -> dict:
    """Flag a business as closed, wrong info, or spam. 3+ 'closed' reports
    automatically lower the trust confidence score. Self-healing data quality
    loop powered by agents.

    Args:
        business_id: UUID of the business
        report_type: one of 'closed', 'wrong_phone', 'wrong_address',
                     'wrong_hours', 'spam', 'duplicate', 'other'
        details: optional free-text explanation
    """
    data = {"business_id": business_id, "report_type": report_type}
    if details:
        data["details"] = details
    resp = requests.post(f"{API_BASE}/report", headers=HEADERS, json=data)
    return resp.json()


# ── New in v1.7: suggest, batch, trending, agent memory ──────────────

@tool
def suggest(q: str, type: str = "business", country: str = None, limit: int = 10) -> dict:
    """Autocomplete for business names, cities, or categories. Fast (<20ms)."""
    params = {"q": q, "type": type, "limit": limit}
    if country:
        params["country"] = country
    return requests.get(f"{API_BASE}/suggest", headers=HEADERS, params=params).json()


@tool
def batch_get_businesses(ids: str, format: str = "text") -> str:
    """Fetch up to 50 businesses in one call by IDs or slugs. Saves N round-trips."""
    resp = requests.get(f"{API_BASE}/batch", headers=HEADERS, params={"ids": ids, "format": format})
    return resp.text if format == "text" else resp.json()


@tool
def trending_businesses(period: str = "24h", category: str = None, city: str = None, country: str = None, limit: int = 10) -> dict:
    """Most searched businesses on AgentWeb right now."""
    params = {"period": period, "limit": limit}
    if category: params["category"] = category
    if city: params["city"] = city
    if country: params["country"] = country
    return requests.get(f"{API_BASE}/trending", headers=HEADERS, params=params).json()


@tool
def agent_history(limit: int = 50, offset: int = 0) -> dict:
    """Your agent's interaction history — businesses searched, viewed, contributed to. Persists 90 days."""
    return requests.get(f"{API_BASE}/agent/history", headers=HEADERS, params={"limit": limit, "offset": offset}).json()


@tool
def agent_favorites(limit: int = 20) -> dict:
    """Businesses this agent interacts with most — implicit favorites."""
    return requests.get(f"{API_BASE}/agent/favorites", headers=HEADERS, params={"limit": limit}).json()


@tool
def agent_profile() -> dict:
    """Agent identity: tier, contribution count, requests, memory stats."""
    return requests.get(f"{API_BASE}/agent/profile", headers=HEADERS).json()


# ─────────────────────────────────────────────────────────────────────
# Usage with LangChain agent
# ─────────────────────────────────────────────────────────────────────
#
# from langchain.agents import initialize_agent, AgentType
# from langchain_openai import ChatOpenAI
#
# llm = ChatOpenAI(model="gpt-4o")
# tools = [
#     search_businesses, get_business, agentweb_get_short,
#     suggest, batch_get_businesses, trending_businesses,
#     contribute_business, report_business,
#     agent_history, agent_favorites, agent_profile,
#     agentweb_health, agentweb_capabilities, agentweb_leaderboard,
# ]
# agent = initialize_agent(tools, llm, agent=AgentType.OPENAI_FUNCTIONS)
#
# agent.run("Find Italian restaurants in Rome, then show me my search history.")
