# Familiar - Self-Hosted AI Companion Platform
# Copyright (c) 2026 George Scott Foley
# ORCID: 0009-0006-4957-0540
# Email: Georgescottfoley@proton.me
# Licensed under the MIT License - see LICENSE file for details

"""
Web API Skill - Argus, the All-Seeing

Argus Panoptes was the hundred-eyed giant who could see everything at once.
He watches all the endpoints of the web and brings back what you seek.

Make HTTP requests to external services.
"""

import json
import logging
import urllib.error
import urllib.parse
import urllib.request

logger = logging.getLogger(__name__)


def fetch_url(data: dict) -> str:
    """Fetch content from a URL."""
    url = data["url"]
    timeout = data.get("timeout", 30)

    try:
        req = urllib.request.Request(url)
        req.add_header("User-Agent", "PiAgent/1.0")

        with urllib.request.urlopen(req, timeout=timeout) as response:
            content = response.read().decode("utf-8", errors="replace")

            # Truncate if too long
            if len(content) > 10000:
                content = content[:10000] + "\n... (truncated)"

            return f"[{response.status}]\n{content}"

    except urllib.error.HTTPError as e:
        return f"HTTP Error {e.code}: {e.reason}"
    except urllib.error.URLError as e:
        return f"URL Error: {e.reason}"
    except Exception as e:
        return f"Error: {str(e)}"


def fetch_json_api(data: dict) -> str:
    """Fetch and parse JSON from an API."""
    url = data["url"]
    headers = data.get("headers", {})
    timeout = data.get("timeout", 30)

    try:
        req = urllib.request.Request(url)
        req.add_header("User-Agent", "PiAgent/1.0")
        req.add_header("Accept", "application/json")

        for key, value in headers.items():
            req.add_header(key, value)

        with urllib.request.urlopen(req, timeout=timeout) as response:
            content = response.read().decode("utf-8")

            # Parse JSON
            try:
                parsed = json.loads(content)
                # Pretty print
                formatted = json.dumps(parsed, indent=2)

                if len(formatted) > 5000:
                    formatted = formatted[:5000] + "\n... (truncated)"

                return formatted
            except json.JSONDecodeError:
                return f"Response is not valid JSON:\n{content[:1000]}"

    except urllib.error.HTTPError as e:
        body = e.read().decode("utf-8", errors="replace")[:500]
        return f"HTTP Error {e.code}: {e.reason}\n{body}"
    except Exception as e:
        return f"Error: {str(e)}"


def post_webhook(data: dict) -> str:
    """Send data to a webhook."""
    url = data["url"]
    payload = data.get("payload", {})
    content_type = data.get("content_type", "application/json")

    try:
        if content_type == "application/json":
            body = json.dumps(payload).encode("utf-8")
        else:
            body = urllib.parse.urlencode(payload).encode("utf-8")

        req = urllib.request.Request(url, data=body, method="POST")
        req.add_header("User-Agent", "PiAgent/1.0")
        req.add_header("Content-Type", content_type)

        with urllib.request.urlopen(req, timeout=30) as response:
            content = response.read().decode("utf-8", errors="replace")
            return f"[{response.status}] {content[:500]}"

    except urllib.error.HTTPError as e:
        body = e.read().decode("utf-8", errors="replace")[:500]
        return f"HTTP Error {e.code}: {e.reason}\n{body}"
    except Exception as e:
        return f"Error: {str(e)}"


def get_weather(data: dict) -> str:
    """Get weather using wttr.in (no API key needed)."""
    location = data.get("location", "")
    format_str = data.get("format", "%l:+%c+%t+%h+%w")

    try:
        # wttr.in provides free weather data
        url = f"https://wttr.in/{urllib.parse.quote(location)}?format={urllib.parse.quote(format_str)}"

        req = urllib.request.Request(url)
        req.add_header("User-Agent", "curl")  # wttr.in responds better to curl

        with urllib.request.urlopen(req, timeout=10) as response:
            return response.read().decode("utf-8").strip()

    except Exception as e:
        return f"Could not fetch weather: {e}"


TOOLS = [
    {
        "name": "fetch_url",
        "description": "Fetch content from a URL (HTML, text, etc.)",
        "input_schema": {
            "type": "object",
            "properties": {
                "url": {"type": "string", "description": "URL to fetch"},
                "timeout": {"type": "integer", "description": "Timeout in seconds", "default": 30},
            },
            "required": ["url"],
        },
        "handler": fetch_url,
        "category": "webapi",
    },
    {
        "name": "fetch_json_api",
        "description": "Call a JSON API and return parsed response",
        "input_schema": {
            "type": "object",
            "properties": {
                "url": {"type": "string", "description": "API URL"},
                "headers": {
                    "type": "object",
                    "description": "Optional headers (e.g., Authorization)",
                    "default": {},
                },
            },
            "required": ["url"],
        },
        "handler": fetch_json_api,
        "category": "webapi",
    },
    {
        "name": "post_webhook",
        "description": "Send data to a webhook URL",
        "input_schema": {
            "type": "object",
            "properties": {
                "url": {"type": "string", "description": "Webhook URL"},
                "payload": {"type": "object", "description": "Data to send", "default": {}},
                "content_type": {
                    "type": "string",
                    "description": "Content type",
                    "enum": ["application/json", "application/x-www-form-urlencoded"],
                    "default": "application/json",
                },
            },
            "required": ["url"],
        },
        "handler": post_webhook,
        "category": "webapi",
    },
    {
        "name": "get_weather",
        "description": "Get current weather for a location",
        "input_schema": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "City name or location (e.g., 'Seattle', 'London')",
                    "default": "",
                }
            },
        },
        "handler": get_weather,
        "category": "webapi",
    },
]
