# 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

"""
Reddit Search & Trends Skill

Search posts, view trending content, and get subreddit top posts.

Setup:
    REDDIT_CLIENT_ID=your_app_id
    REDDIT_CLIENT_SECRET=your_secret

Create an app at: https://www.reddit.com/prefs/apps
API: https://oauth.reddit.com/
"""

import base64
import logging
import time

from familiar.core.api_cache import cached
from familiar.skills._api_utils import (
    APIError,
    api_get,
    get_env,
)

logger = logging.getLogger(__name__)

BASE_URL = "https://oauth.reddit.com"
TOKEN_URL = "https://www.reddit.com/api/v1/access_token"

_token_cache: dict = {"token": "", "expires": 0}


def _client_id() -> str:
    return get_env("REDDIT_CLIENT_ID") or ""


def _client_secret() -> str:
    return get_env("REDDIT_CLIENT_SECRET") or ""


def _user_agent() -> str:
    return get_env("REDDIT_USER_AGENT") or "Familiar:v1.0 (by /u/familiar-agent)"


def _check_config() -> str:
    if not _client_id() or not _client_secret():
        return (
            "Reddit not configured.\n"
            "Set REDDIT_CLIENT_ID and REDDIT_CLIENT_SECRET.\n"
            "Create an app at: https://www.reddit.com/prefs/apps"
        )
    return ""


def _get_access_token() -> str:
    """Get OAuth access token using client credentials grant."""
    now = time.time()
    if _token_cache["token"] and _token_cache["expires"] > now:
        return _token_cache["token"]

    try:
        import httpx

        creds = base64.b64encode(f"{_client_id()}:{_client_secret()}".encode()).decode()
        resp = httpx.post(
            TOKEN_URL,
            headers={
                "Authorization": f"Basic {creds}",
                "User-Agent": _user_agent(),
            },
            data={"grant_type": "client_credentials"},
            timeout=15,
        )
        resp.raise_for_status()
        data = resp.json()

        token = data.get("access_token", "")
        expires_in = data.get("expires_in", 3600)
        _token_cache["token"] = token
        _token_cache["expires"] = now + expires_in - 60

        return token
    except Exception as e:
        logger.error("Reddit token error: %s", e)
        return ""


def _headers() -> dict:
    token = _get_access_token()
    return {
        "Authorization": f"Bearer {token}",
        "User-Agent": _user_agent(),
    }


def _format_post(i: int, post: dict) -> list[str]:
    """Format a single Reddit post for display."""
    data = post.get("data", post)
    title = data.get("title", "")
    author = data.get("author", "[deleted]")
    subreddit = data.get("subreddit_name_prefixed", data.get("subreddit", ""))
    score = data.get("score", 0)
    comments = data.get("num_comments", 0)
    created = data.get("created_utc", 0)
    permalink = data.get("permalink", "")

    age = ""
    if created:
        hours = (time.time() - created) / 3600
        if hours < 1:
            age = f"{int(hours * 60)}m ago"
        elif hours < 24:
            age = f"{int(hours)}h ago"
        else:
            age = f"{int(hours / 24)}d ago"

    lines = [f"{i}. **{title}**"]
    details = []
    if subreddit:
        details.append(subreddit)
    details.append(f"u/{author}")
    details.append(f"{score:,} pts")
    details.append(f"{comments} comments")
    if age:
        details.append(age)
    lines.append(f"   {' | '.join(details)}")
    if permalink:
        lines.append(f"   https://reddit.com{permalink}")
    return lines


# ---------------------------------------------------------------------------
# Tool handlers
# ---------------------------------------------------------------------------


def reddit_search(data: dict) -> str:
    """Search Reddit posts."""
    err = _check_config()
    if err:
        return err

    query = data.get("query", "").strip()
    if not query:
        return "Please provide a search query."

    sort = data.get("sort", "relevance")
    time_filter = data.get("time_filter", "week")
    subreddit = data.get("subreddit", "")
    limit = min(int(data.get("limit", 10)), 25)

    try:
        result = _search_cached(query, sort, time_filter, subreddit, limit)

        posts = result.get("data", {}).get("children", [])
        if not posts:
            return f"No results for '{query}'."

        lines = [f"**Reddit Search: '{query}'** ({len(posts)} results):", ""]
        for i, post in enumerate(posts, 1):
            lines.extend(_format_post(i, post))
            lines.append("")

        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("Reddit search error: %s", e)
        return f"Error searching Reddit: {e}"


@cached(prefix="reddit_search", ttl=120)
def _search_cached(query: str, sort: str, time_filter: str, subreddit: str, limit: int) -> dict:
    endpoint = f"{BASE_URL}/r/{subreddit}/search" if subreddit else f"{BASE_URL}/search"
    params = {
        "q": query,
        "sort": sort,
        "t": time_filter,
        "limit": limit,
        "restrict_sr": "true" if subreddit else "false",
    }
    return api_get(
        endpoint,
        params=params,
        headers=_headers(),
        service_name="Reddit",
    )


def reddit_trending(data: dict) -> str:
    """Get trending/hot posts from a subreddit."""
    err = _check_config()
    if err:
        return err

    subreddit = data.get("subreddit", "all")
    limit = min(int(data.get("limit", 10)), 25)

    try:
        result = _trending_cached(subreddit, limit)

        posts = result.get("data", {}).get("children", [])
        if not posts:
            return f"No trending posts in r/{subreddit}."

        lines = [f"**Hot in r/{subreddit}** ({len(posts)} posts):", ""]
        for i, post in enumerate(posts, 1):
            lines.extend(_format_post(i, post))
            lines.append("")

        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("Reddit trending error: %s", e)
        return f"Error fetching trending: {e}"


@cached(prefix="reddit_trending", ttl=120)
def _trending_cached(subreddit: str, limit: int) -> dict:
    return api_get(
        f"{BASE_URL}/r/{subreddit}/hot",
        params={"limit": limit},
        headers=_headers(),
        service_name="Reddit",
    )


def subreddit_top(data: dict) -> str:
    """Get top posts from a subreddit."""
    err = _check_config()
    if err:
        return err

    subreddit = data.get("subreddit", "all")
    time_filter = data.get("time_filter", "week")
    limit = min(int(data.get("limit", 10)), 25)

    try:
        result = _top_cached(subreddit, time_filter, limit)

        posts = result.get("data", {}).get("children", [])
        if not posts:
            return f"No top posts in r/{subreddit} ({time_filter})."

        lines = [f"**Top in r/{subreddit}** (this {time_filter}, {len(posts)} posts):", ""]
        for i, post in enumerate(posts, 1):
            lines.extend(_format_post(i, post))
            lines.append("")

        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("Reddit top error: %s", e)
        return f"Error fetching top posts: {e}"


@cached(prefix="reddit_top", ttl=120)
def _top_cached(subreddit: str, time_filter: str, limit: int) -> dict:
    return api_get(
        f"{BASE_URL}/r/{subreddit}/top",
        params={"t": time_filter, "limit": limit},
        headers=_headers(),
        service_name="Reddit",
    )


# ---------------------------------------------------------------------------
# Tool definitions
# ---------------------------------------------------------------------------

TOOLS = [
    {
        "name": "reddit_search",
        "description": "Search Reddit posts by keyword with sorting and time filters.",
        "input_schema": {
            "type": "object",
            "properties": {
                "query": {"type": "string", "description": "Search query"},
                "sort": {
                    "type": "string",
                    "description": "Sort: relevance, hot, top, new, comments",
                    "default": "relevance",
                },
                "time_filter": {
                    "type": "string",
                    "description": "Time: hour, day, week, month, year, all",
                    "default": "week",
                },
                "subreddit": {
                    "type": "string",
                    "description": "Restrict to subreddit (omit for all)",
                },
                "limit": {
                    "type": "integer",
                    "description": "Max results (1-25, default 10)",
                    "default": 10,
                },
            },
            "required": ["query"],
        },
        "handler": reddit_search,
        "category": "reddit",
    },
    {
        "name": "reddit_trending",
        "description": "Get trending/hot posts from a subreddit or r/all.",
        "input_schema": {
            "type": "object",
            "properties": {
                "subreddit": {
                    "type": "string",
                    "description": "Subreddit name (default: all)",
                    "default": "all",
                },
                "limit": {
                    "type": "integer",
                    "description": "Max posts (1-25, default 10)",
                    "default": 10,
                },
            },
        },
        "handler": reddit_trending,
        "category": "reddit",
    },
    {
        "name": "subreddit_top",
        "description": "Get top-rated posts from a subreddit by time period.",
        "input_schema": {
            "type": "object",
            "properties": {
                "subreddit": {
                    "type": "string",
                    "description": "Subreddit name (default: all)",
                    "default": "all",
                },
                "time_filter": {
                    "type": "string",
                    "description": "Period: hour, day, week, month, year, all",
                    "default": "week",
                },
                "limit": {
                    "type": "integer",
                    "description": "Max posts (1-25, default 10)",
                    "default": 10,
                },
            },
        },
        "handler": subreddit_top,
        "category": "reddit",
    },
]
