"""MCP server for broken link finding and contact discovery."""

import asyncio
import json
from dataclasses import asdict
from typing import Optional

from mcp.server.fastmcp import FastMCP

from .crawler import BrokenLinkFinder
from .contacts import ContactFinder

mcp = FastMCP(
    "broken-link-finder",
    instructions="Find broken outbound links on websites and discover contact emails for outreach.",
)


@mcp.tool()
async def find_broken_links(
    url: str,
    label: str = "",
    delay: float = 1.0,
    include_contacts: bool = True,
) -> str:
    """Crawl a web page and find all broken outbound links.

    Checks every external link on the page and reports which ones return
    4xx/5xx errors or time out. Optionally discovers contact emails for
    the site (from the page, contact pages, and Hunter.io if configured).

    Args:
        url: The page URL to crawl for broken links.
        label: Optional label for the site (e.g. university name).
        delay: Seconds to wait between link checks (default 1.0). Be polite.
        include_contacts: Whether to also find contact emails for the site.
    """
    contact_emails = []
    page_html = None

    async with BrokenLinkFinder(delay=delay) as finder:
        # Fetch the page first so we can reuse HTML for contact extraction
        page_html, status, error = await finder.fetch_page(url)
        if not page_html:
            return json.dumps({"error": f"Could not fetch {url}: {error}"})

        if include_contacts:
            cf = ContactFinder()
            contact_emails = await cf.find_emails(url, page_html=page_html)

        result = await finder.crawl_page(url, label=label, contact_emails=contact_emails)

    output = {
        "url": result.url,
        "label": result.label,
        "total_outbound_links": result.total_links,
        "broken_link_count": len(result.broken_links),
        "crawl_time_seconds": round(result.crawl_time, 1),
        "contact_emails": contact_emails,
        "broken_links": [asdict(bl) for bl in result.broken_links],
    }
    return json.dumps(output, indent=2)


@mcp.tool()
async def check_url(url: str) -> str:
    """Check if a single URL is reachable or broken.

    Returns the HTTP status code and any error message.

    Args:
        url: The URL to check.
    """
    async with BrokenLinkFinder() as finder:
        status_code, error_msg = await finder.check_link(url)

    is_broken = status_code >= 400 or status_code == 0
    return json.dumps({
        "url": url,
        "status_code": status_code,
        "is_broken": is_broken,
        "error": error_msg,
    })


@mcp.tool()
async def find_contact_emails(
    url: str,
    hunter_api_key: Optional[str] = None,
) -> str:
    """Find contact emails for a website.

    Discovers emails by:
    1. Scraping the given URL for mailto links and email patterns
    2. Checking common contact page paths (/contact, /about, etc.)
    3. Using Hunter.io API if an API key is provided or HUNTER_API_KEY is set

    Emails are scored and sorted by outreach relevance (webmaster/editor/marketing
    emails rank highest, free email providers rank lowest).

    Args:
        url: The website URL to find contacts for.
        hunter_api_key: Optional Hunter.io API key. Falls back to HUNTER_API_KEY env var.
    """
    cf = ContactFinder(hunter_api_key=hunter_api_key)
    emails = await cf.find_emails(url)

    return json.dumps({
        "url": url,
        "emails": emails,
        "count": len(emails),
    }, indent=2)


def main():
    mcp.run()


if __name__ == "__main__":
    main()
