# 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

"""Tests for Sprint 9 skills: Compliance Calendar, Reddit, Open Referral."""

from unittest.mock import MagicMock, patch

HTTPX_GET = "familiar.skills._api_utils.httpx.get"
HTTPX_POST = "familiar.skills._api_utils.httpx.post"
CACHE_GET = "familiar.core.api_cache.get_cached"
CACHE_SET = "familiar.core.api_cache.set_cached"

# ── Env helpers ──────────────────────────────────────────────────────────────

REDDIT_ENV = {
    "REDDIT_CLIENT_ID": "test_client_id",
    "REDDIT_CLIENT_SECRET": "test_client_secret",
    "REDDIT_USER_AGENT": "TestApp:v1.0",
}
OR_ENV = {
    "OPEN_REFERRAL_URL": "https://api.example-211.org",
    "OPEN_REFERRAL_API_KEY": "or_test_key",
}


def _reddit_env(key: str) -> str:
    return REDDIT_ENV.get(key, "")


def _or_env(key: str) -> str:
    return OR_ENV.get(key, "")


def _mock_response(data, status_code=200):
    resp = MagicMock()
    resp.status_code = status_code
    resp.json.return_value = data
    resp.raise_for_status = MagicMock()
    return resp


# ── Compliance Calendar tests ────────────────────────────────────────────────


class TestFilingDeadlines:
    def test_returns_deadlines(self):
        from familiar.skills.compliance.skill import filing_deadlines

        result = filing_deadlines({"months_ahead": 12})
        assert "IRS Deadlines" in result
        assert "Form" in result

    def test_private_foundation(self):
        from familiar.skills.compliance.skill import filing_deadlines

        result = filing_deadlines({"months_ahead": 12, "org_type": "private_foundation"})
        assert "990-PF" in result


class TestStateRequirements:
    def test_all_states(self):
        from familiar.skills.compliance.skill import state_requirements

        result = state_requirements({})
        assert "State Registration" in result
        assert "CA" in result

    def test_specific_state(self):
        from familiar.skills.compliance.skill import state_requirements

        result = state_requirements({"state": "NY"})
        assert "NY" in result
        assert "CHAR500" in result

    def test_unknown_state(self):
        from familiar.skills.compliance.skill import state_requirements

        result = state_requirements({"state": "ZZ"})
        assert "No specific requirements" in result


class TestComplianceChecklist:
    def test_full_checklist(self):
        from familiar.skills.compliance.skill import compliance_checklist

        result = compliance_checklist({})
        assert "Compliance Checklist" in result
        assert "Form 990" in result

    def test_filtered(self):
        from familiar.skills.compliance.skill import compliance_checklist

        result = compliance_checklist({"category": "board"})
        assert "Board" in result


class TestComplianceTools:
    def test_tools_registered(self):
        from familiar.skills.compliance.skill import TOOLS

        names = {t["name"] for t in TOOLS}
        assert "filing_deadlines" in names
        assert "state_requirements" in names
        assert "compliance_checklist" in names


# ── Reddit tests ─────────────────────────────────────────────────────────────


class TestRedditSearch:
    def test_no_config(self):
        from familiar.skills.reddit.skill import reddit_search

        with patch("familiar.skills.reddit.skill.get_env", return_value=""):
            result = reddit_search({})
        assert "not configured" in result.lower()

    def test_no_query(self):
        from familiar.skills.reddit.skill import reddit_search

        with patch("familiar.skills.reddit.skill.get_env", side_effect=_reddit_env):
            result = reddit_search({})
        assert "query" in result.lower()

    def test_success(self):
        import time

        from familiar.skills.reddit.skill import reddit_search

        api_resp = _mock_response(
            {
                "data": {
                    "children": [
                        {
                            "data": {
                                "title": "AI trends in 2026",
                                "author": "test_user",
                                "subreddit_name_prefixed": "r/technology",
                                "score": 1500,
                                "num_comments": 200,
                                "created_utc": time.time() - 3600,
                                "permalink": "/r/technology/comments/abc/ai_trends/",
                            }
                        }
                    ]
                }
            }
        )
        with (
            patch("familiar.skills.reddit.skill.get_env", side_effect=_reddit_env),
            patch(
                "familiar.skills.reddit.skill._get_access_token",
                return_value="test_token",
            ),
            patch(HTTPX_GET, return_value=api_resp),
            patch(CACHE_GET, return_value=None),
            patch(CACHE_SET),
        ):
            result = reddit_search({"query": "AI trends"})
        assert "AI trends in 2026" in result
        assert "1,500 pts" in result


class TestRedditTrending:
    def test_success(self):
        import time

        from familiar.skills.reddit.skill import reddit_trending

        api_resp = _mock_response(
            {
                "data": {
                    "children": [
                        {
                            "data": {
                                "title": "Breaking: major update",
                                "author": "news_bot",
                                "subreddit": "news",
                                "score": 5000,
                                "num_comments": 800,
                                "created_utc": time.time() - 1800,
                                "permalink": "/r/news/comments/xyz/breaking/",
                            }
                        }
                    ]
                }
            }
        )
        with (
            patch("familiar.skills.reddit.skill.get_env", side_effect=_reddit_env),
            patch(
                "familiar.skills.reddit.skill._get_access_token",
                return_value="test_token",
            ),
            patch(HTTPX_GET, return_value=api_resp),
            patch(CACHE_GET, return_value=None),
            patch(CACHE_SET),
        ):
            result = reddit_trending({"subreddit": "news"})
        assert "Breaking" in result
        assert "5,000 pts" in result


class TestSubredditTop:
    def test_success(self):
        import time

        from familiar.skills.reddit.skill import subreddit_top

        api_resp = _mock_response(
            {
                "data": {
                    "children": [
                        {
                            "data": {
                                "title": "Top post of the week",
                                "author": "top_poster",
                                "subreddit": "all",
                                "score": 90000,
                                "num_comments": 3000,
                                "created_utc": time.time() - 86400,
                                "permalink": "/r/all/comments/top/weekly/",
                            }
                        }
                    ]
                }
            }
        )
        with (
            patch("familiar.skills.reddit.skill.get_env", side_effect=_reddit_env),
            patch(
                "familiar.skills.reddit.skill._get_access_token",
                return_value="test_token",
            ),
            patch(HTTPX_GET, return_value=api_resp),
            patch(CACHE_GET, return_value=None),
            patch(CACHE_SET),
        ):
            result = subreddit_top({})
        assert "Top post" in result
        assert "90,000 pts" in result


class TestRedditTools:
    def test_tools_registered(self):
        from familiar.skills.reddit.skill import TOOLS

        names = {t["name"] for t in TOOLS}
        assert "reddit_search" in names
        assert "reddit_trending" in names
        assert "subreddit_top" in names


# ── Open Referral tests ──────────────────────────────────────────────────────


class TestFindServices:
    def test_no_config(self):
        from familiar.skills.open_referral.skill import find_services

        with patch("familiar.skills.open_referral.skill.get_env", return_value=""):
            result = find_services({})
        assert "not configured" in result.lower()

    def test_no_query(self):
        from familiar.skills.open_referral.skill import find_services

        with patch("familiar.skills.open_referral.skill.get_env", side_effect=_or_env):
            result = find_services({})
        assert "query" in result.lower()

    def test_success(self):
        from familiar.skills.open_referral.skill import find_services

        resp = _mock_response(
            {
                "total_items": 5,
                "contents": [
                    {
                        "id": "svc-001",
                        "name": "Community Food Pantry",
                        "description": "Weekly food distribution for families in need.",
                        "organization": {"name": "Local Food Bank"},
                    }
                ],
            }
        )
        with (
            patch("familiar.skills.open_referral.skill.get_env", side_effect=_or_env),
            patch(HTTPX_GET, return_value=resp),
            patch(CACHE_GET, return_value=None),
            patch(CACHE_SET),
        ):
            result = find_services({"query": "food assistance"})
        assert "Community Food Pantry" in result
        assert "Local Food Bank" in result


class TestServiceDetails:
    def test_no_id(self):
        from familiar.skills.open_referral.skill import service_details

        with patch("familiar.skills.open_referral.skill.get_env", side_effect=_or_env):
            result = service_details({})
        assert "service_id" in result.lower()

    def test_success(self):
        from familiar.skills.open_referral.skill import service_details

        resp = _mock_response(
            {
                "id": "svc-001",
                "name": "Community Food Pantry",
                "description": "Weekly food distribution.",
                "organization": {"name": "Local Food Bank"},
                "service_at_locations": [
                    {
                        "location": {
                            "name": "Downtown Center",
                            "address": {
                                "street_address": "123 Main St",
                                "city": "Springfield",
                                "state": "IL",
                                "postal_code": "62704",
                            },
                        }
                    }
                ],
                "contacts": [
                    {"name": "Jane Smith", "phone": "555-0123", "email": "jane@foodbank.org"}
                ],
            }
        )
        with (
            patch("familiar.skills.open_referral.skill.get_env", side_effect=_or_env),
            patch(HTTPX_GET, return_value=resp),
            patch(CACHE_GET, return_value=None),
            patch(CACHE_SET),
        ):
            result = service_details({"service_id": "svc-001"})
        assert "Community Food Pantry" in result
        assert "123 Main St" in result
        assert "Jane Smith" in result


class TestFindOrganizations:
    def test_success(self):
        from familiar.skills.open_referral.skill import find_organizations

        resp = _mock_response(
            {
                "total_items": 3,
                "contents": [
                    {
                        "id": "org-001",
                        "name": "United Way",
                        "description": "Community impact organization.",
                    }
                ],
            }
        )
        with (
            patch("familiar.skills.open_referral.skill.get_env", side_effect=_or_env),
            patch(HTTPX_GET, return_value=resp),
            patch(CACHE_GET, return_value=None),
            patch(CACHE_SET),
        ):
            result = find_organizations({"query": "united way"})
        assert "United Way" in result


class TestOpenReferralTools:
    def test_tools_registered(self):
        from familiar.skills.open_referral.skill import TOOLS

        names = {t["name"] for t in TOOLS}
        assert "find_services" in names
        assert "service_details" in names
        assert "find_organizations" in names
