from __future__ import annotations

import json
import os
from typing import Any

import httpx
from mcp.server.fastmcp import FastMCP

mcp = FastMCP(
    "Heron Intelligence",
    instructions=(
        "Heron Intelligence provides financial research intelligence based on curated earnings call "
        "transcripts and due diligence interviews. Use search_company first to find a company, then "
        "use the other tools to retrieve and analyze its transcripts."
    ),
)

_API_URL = "https://ubjzp9xp6w.us-west-2.awsapprunner.com"
_API_KEY = os.environ.get("HERON_API_KEY", "")
_TIMEOUT = float(os.environ.get("HERON_TIMEOUT", "120.0"))


def _headers() -> dict[str, str]:
    return {"X-API-KEY": _API_KEY, "Content-Type": "application/json"}


def _check_config() -> str | None:
    if not _API_KEY:
        return "HERON_API_KEY is not set. Add it to the MCP server environment config."
    return None


class QuotaExceededError(Exception):
    """Raised when the API returns HTTP 429."""


def _quota_error_message(resp: httpx.Response) -> str:
    """Return a human-readable message for 429 quota responses."""
    reset_at = resp.headers.get("X-Quota-Reset", "")
    retry_after = resp.headers.get("Retry-After", "")
    try:
        detail = resp.json().get("detail", "Quota exceeded.")
    except Exception:
        detail = "Quota exceeded."
    msg = f"Heron Intelligence quota limit reached: {detail}"
    if reset_at:
        msg += f" Your quota resets at {reset_at}."
    elif retry_after:
        msg += f" Retry after {retry_after} seconds."
    msg += " Please contact us to upgrade your plan."
    return msg


async def _post(path: str, body: dict) -> dict[str, Any]:
    async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
        resp = await client.post(f"{_API_URL}{path}", json=body, headers=_headers())
        if resp.status_code == 429:
            raise QuotaExceededError(_quota_error_message(resp))
        resp.raise_for_status()
        return resp.json()


async def _get(path: str) -> dict[str, Any]:
    async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
        resp = await client.get(f"{_API_URL}{path}", headers=_headers())
        if resp.status_code == 429:
            raise QuotaExceededError(_quota_error_message(resp))
        resp.raise_for_status()
        return resp.json()


@mcp.tool()
async def search_company(query: str) -> str:
    """
    Search for a company in the Heron Intelligence catalog by name, ticker, or description.

    Use this FIRST before calling any other tool. Returns the company ID needed
    by other tools.

    Args:
        query: Free-text search — company name, ticker symbol, or description
               (e.g. "Nubank", "MELI", "Mexican fintech unicorn")

    Returns:
        JSON with matched company: id, name, ticker, exchange.
        Returns an error message if no match is found.
    """
    err = _check_config()
    if err:
        return json.dumps({"error": err})
    try:
        data = await _post("/api/v1/companies/search", {"query": query})
        return json.dumps(data, ensure_ascii=False)
    except QuotaExceededError as exc:
        return json.dumps({"error": str(exc)})
    except httpx.HTTPStatusError as exc:
        return json.dumps({"error": f"API {exc.response.status_code}: {exc.response.text}"})
    except Exception as exc:
        return json.dumps({"error": str(exc)})


@mcp.tool()
async def get_recent_transcripts(company_id: str, quarters: int = 3) -> str:
    """
    List the most recent transcripts available for a company.

    Use this after search_company to see what research materials are available
    before running a full analysis.

    Args:
        company_id: The company ID returned by search_company
        quarters:   How many past quarters to look back (default: 3)

    Returns:
        JSON list of transcript metadata: title, date, due_diligence_type,
        source_tone, call_quality, and id.
    """
    err = _check_config()
    if err:
        return json.dumps({"error": err})
    try:
        data = await _post(
            "/api/v1/transcripts/search",
            {"company_id": company_id, "quarters": quarters},
        )
        return json.dumps(data, ensure_ascii=False)
    except QuotaExceededError as exc:
        return json.dumps({"error": str(exc)})
    except httpx.HTTPStatusError as exc:
        return json.dumps({"error": f"API {exc.response.status_code}: {exc.response.text}"})
    except Exception as exc:
        return json.dumps({"error": str(exc)})


@mcp.tool()
async def analyze_red_flags(company: str, quarters: int = 3) -> str:
    """
    Deep analysis of risk signals and red flags for a company using Heron Intelligence's
    ReAct agent powered by curated transcripts and due diligence interviews.

    This is the primary analytical tool. It automatically searches for the
    company, retrieves relevant transcripts, and produces a structured risk
    analysis with citations.

    Args:
        company: Company name or ticker (e.g. "Rappi", "MELI", "Nubank")
        quarters: How many past quarters to analyze (default: 3)

    Returns:
        Structured markdown analysis with red flags by category, severity,
        trend, and auditable source citations.
    """
    err = _check_config()
    if err:
        return err
    try:
        prompt = (
            f"Perform a comprehensive red flag analysis for **{company}** "
            f"covering the last {quarters} quarters.\n\n"
            "Structure your response as follows:\n"
            "1. **Executive Summary** — 2-3 sentence overview of the risk profile\n"
            "2. **Red Flags** — organized by category (Operational, Financial, Management, "
            "Competitive, Macro). For each flag: description, severity (high/medium/low), "
            "trend (improving/worsening/stable), and source citations\n"
            "3. **Positive Signals** — counter-evidence or strengths worth noting\n"
            "4. **Overall Risk Assessment** — high / medium / low with rationale\n\n"
            "Include [Document Type: conversation](ID) citations for every claim. "
            "If no transcripts are found for this company, clearly state that."
        )
        data = await _post("/api/v1/agents/aura/query", {"query": prompt})
        return data.get("response", json.dumps(data, ensure_ascii=False))
    except QuotaExceededError as exc:
        return str(exc)
    except httpx.HTTPStatusError as exc:
        return f"API error {exc.response.status_code}: {exc.response.text}"
    except Exception as exc:
        return f"Error running analysis: {str(exc)}"


@mcp.tool()
async def get_transcript_content(transcript_id: str) -> str:
    """
    Retrieve the full content of a specific transcript including all Q&A pairs.

    Use this when you need verbatim quotes or want to read the full context of
    a document returned by get_recent_transcripts or cited in analyze_red_flags.

    Args:
        transcript_id: The UUID of the transcript

    Returns:
        JSON with the full transcript payload including Q&A pairs, speakers,
        call date, and metadata.
    """
    err = _check_config()
    if err:
        return json.dumps({"error": err})
    try:
        data = await _get(f"/api/v1/transcripts/{transcript_id}")
        return json.dumps(data, ensure_ascii=False)
    except QuotaExceededError as exc:
        return json.dumps({"error": str(exc)})
    except httpx.HTTPStatusError as exc:
        if exc.response.status_code == 404:
            return json.dumps({"found": False, "message": f"No transcript found: '{transcript_id}'"})
        return json.dumps({"error": f"API {exc.response.status_code}: {exc.response.text}"})
    except Exception as exc:
        return json.dumps({"error": str(exc)})
