"""MCP Tools for analytics queries.

Provides a tool to execute read-only SQL queries against per-tenant
analytics data (synced from Platform APIs into PostgreSQL).
"""

import json
from typing import Any

from mcp.types import TextContent, Tool

from ..client import Platform2StepClient

ANALYTICS_TOOLS: list[Tool] = [
    Tool(
        name="query_analytics_db",
        description="""Execute a read-only SQL query against the company's analytics database.

The analytics DB contains 7 tables synced from the Platform API:

TABLES AND COLUMNS:
- bookings: id, client_id, service_id, provider_id, location_id, start_time, end_time, status, price, notes, created_at
  status values: pending, confirmed, completed, cancelled, no_show
- services: id, name, category_id, duration, price, active, company_id
- categories: id, name, "order", company_id
- providers: id, name, email, active, company_id
- locations: id, name, address, phone, timezone, company_id
- transactions: id, booking_id, amount, status, payment_method, paid_at, created_at
  status values: pending, completed, refunded, failed
- clients: id, name, email, phone, created_at

RELATIONSHIPS:
- bookings.service_id → services.id
- bookings.client_id → clients.id
- bookings.provider_id → providers.id
- bookings.location_id → locations.id
- services.category_id → categories.id
- transactions.booking_id → bookings.id

EXAMPLE QUERIES:
1. No-shows last 30 days:
   SELECT c.name, COUNT(*) as no_shows
   FROM bookings b JOIN clients c ON b.client_id = c.id
   WHERE b.status = 'no_show' AND b.start_time > NOW() - INTERVAL '30 days'
   GROUP BY c.name ORDER BY no_shows DESC LIMIT 10

2. Revenue by service:
   SELECT s.name, SUM(t.amount) as revenue, COUNT(*) as bookings
   FROM transactions t
   JOIN bookings b ON t.booking_id = b.id
   JOIN services s ON b.service_id = s.id
   WHERE t.status = 'completed'
   GROUP BY s.name ORDER BY revenue DESC

3. Unpaid bookings:
   SELECT b.id, c.name, s.name as service, b.start_time, b.price
   FROM bookings b
   JOIN clients c ON b.client_id = c.id
   JOIN services s ON b.service_id = s.id
   LEFT JOIN transactions t ON t.booking_id = b.id AND t.status = 'completed'
   WHERE b.status = 'completed' AND t.id IS NULL
   ORDER BY b.start_time DESC

4. Provider occupancy:
   SELECT p.name, COUNT(*) as total_bookings,
     COUNT(CASE WHEN b.status = 'completed' THEN 1 END) as completed,
     COUNT(CASE WHEN b.status = 'no_show' THEN 1 END) as no_shows
   FROM providers p
   LEFT JOIN bookings b ON b.provider_id = p.id
     AND b.start_time > NOW() - INTERVAL '30 days'
   WHERE p.active = true
   GROUP BY p.name ORDER BY total_bookings DESC

5. Recurring clients:
   SELECT c.name, c.email, COUNT(*) as visits,
     MAX(b.start_time) as last_visit
   FROM clients c JOIN bookings b ON b.client_id = c.id
   WHERE b.status IN ('completed', 'confirmed')
   GROUP BY c.name, c.email HAVING COUNT(*) > 1
   ORDER BY visits DESC LIMIT 20

NOTES:
- Only SELECT queries allowed (no INSERT/UPDATE/DELETE)
- Max 1000 rows returned. Use LIMIT and aggregations.
- Data freshness: check data_as_of and sync_lag_seconds in response
- Use JOINs, CTEs, window functions as needed
- Column "order" in categories must be quoted: "order"
""",
        inputSchema={
            "type": "object",
            "properties": {
                "company_id": {
                    "type": "integer",
                    "description": "Company ID to query analytics for",
                },
                "sql": {
                    "type": "string",
                    "description": "SQL SELECT query to execute",
                },
                "freshness_policy": {
                    "type": "string",
                    "enum": ["allow_stale", "require_fresh"],
                    "description": "Whether to allow stale data (default) or require fresh sync",
                    "default": "allow_stale",
                },
            },
            "required": ["company_id", "sql"],
        },
    ),
    Tool(
        name="get_analytics_status",
        description="Get the analytics sync status for a company. Shows whether data is ready, when it was last synced, and which tables are available.",
        inputSchema={
            "type": "object",
            "properties": {
                "company_id": {
                    "type": "integer",
                    "description": "Company ID to check analytics status for",
                },
            },
            "required": ["company_id"],
        },
    ),
    Tool(
        name="refresh_analytics_data",
        description="""Force an immediate refresh of analytics data for a company.

Use this when the user explicitly asks to update/refresh their analytics data,
or when the data_as_of timestamp from a previous query is too old for the user's needs.

This bypasses the normal 30-minute TTL and enqueues a high-priority sync job.
If a sync is already in progress or queued, this returns a message indicating so.
If the last sync failed recently (5 min cooldown), returns a conflict error.

After triggering a refresh, use get_analytics_status to check progress,
then retry your query once the state is READY (typically 10-15 seconds).""",
        inputSchema={
            "type": "object",
            "properties": {
                "company_id": {
                    "type": "integer",
                    "description": "Company ID to refresh analytics data for",
                },
            },
            "required": ["company_id"],
        },
    ),
]


async def handle_analytics_tool(
    name: str,
    arguments: dict[str, Any],
    client: Platform2StepClient,
) -> list[TextContent]:
    """Handle analytics tool calls."""

    if name == "query_analytics_db":
        company_id = arguments["company_id"]
        sql = arguments["sql"]
        freshness_policy = arguments.get("freshness_policy", "allow_stale")

        result = await client.query_analytics(
            company_id=company_id,
            sql=sql,
            freshness_policy=freshness_policy,
        )

        # Check if warming up
        if "error" in result and result["error"] == "warming_up":
            return [
                TextContent(
                    type="text",
                    text=(
                        f"Analytics data is being prepared for company {company_id}.\n\n"
                        f"Message: {result.get('message', 'Sync in progress')}\n"
                        f"Estimated wait: {result.get('estimated_wait_seconds', 12)} seconds\n\n"
                        "Please retry the query in a few seconds."
                    ),
                )
            ]

        # Format as markdown table
        columns = result.get("columns", [])
        rows = result.get("rows", [])

        if not columns:
            text = "_No results_"
        else:
            # Header
            header = "| " + " | ".join(str(c) for c in columns) + " |"
            separator = "| " + " | ".join("---" for _ in columns) + " |"
            lines = [header, separator]
            for row in rows:
                formatted = "| " + " | ".join(
                    str(v) if v is not None else "" for v in row
                ) + " |"
                lines.append(formatted)
            text = "\n".join(lines)

        # Add metadata
        metadata_parts = []
        if result.get("row_count") is not None:
            metadata_parts.append(f"Rows: {result['row_count']}")
        if result.get("truncated"):
            metadata_parts.append("(TRUNCATED - add LIMIT or filters)")
        if result.get("data_as_of"):
            metadata_parts.append(f"Data as of: {result['data_as_of']}")
        if result.get("sync_lag_seconds") is not None:
            lag = result["sync_lag_seconds"]
            if lag > 3600:
                metadata_parts.append(f"Sync lag: {lag // 3600}h {(lag % 3600) // 60}m")
            elif lag > 60:
                metadata_parts.append(f"Sync lag: {lag // 60}m")
            else:
                metadata_parts.append(f"Sync lag: {lag}s")
        if result.get("snapshot_version"):
            metadata_parts.append(f"Snapshot: {result['snapshot_version']}")
        if result.get("is_partial"):
            metadata_parts.append("(PARTIAL - some tables not yet synced)")

        if metadata_parts:
            text += "\n\n_" + " | ".join(metadata_parts) + "_"

        return [TextContent(type="text", text=text)]

    elif name == "get_analytics_status":
        company_id = arguments["company_id"]
        result = await client.get_analytics_status(company_id=company_id)
        return [TextContent(type="text", text=json.dumps(result, indent=2))]

    elif name == "refresh_analytics_data":
        company_id = arguments["company_id"]
        result = await client.refresh_analytics(company_id=company_id)

        if "error" in result:
            # 409 cooldown case
            return [
                TextContent(
                    type="text",
                    text=(
                        f"Cannot refresh analytics data for company {company_id} right now.\n\n"
                        f"Reason: {result.get('message', 'Sync cooldown active')}\n\n"
                        "Please try again later."
                    ),
                )
            ]

        return [
            TextContent(
                type="text",
                text=(
                    f"Analytics refresh triggered for company {company_id}.\n\n"
                    f"Status: {result.get('message', 'Sync enqueued')}\n\n"
                    "Use `get_analytics_status` to check progress, then retry your query "
                    "once the state is READY (typically 10-15 seconds)."
                ),
            )
        ]

    raise ValueError(f"Unknown analytics tool: {name}")
