# 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

"""
Unit tests for multi-account email menu (sentinel-based account selection).
"""

import sys
from pathlib import Path
from unittest.mock import MagicMock, patch

import pytest

sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent))

from familiar.core.confirmations import EMAIL_MENU_PREFIX
from familiar.skills.email.skill import _check_all_inboxes, _extract_summary

# ── _extract_summary tests ───────────────────────────────────────────────────


class TestExtractSummary:
    def test_unread_count(self):
        assert _extract_summary("📬 5 unread emails (Gmail API):") == "5 unread"

    def test_single_email(self):
        assert _extract_summary("📬 1 email found:") == "1 unread"

    def test_no_unread(self):
        assert _extract_summary("📬 No unread emails") == "0 unread"

    def test_no_emails(self):
        assert _extract_summary("No emails found") == "0 unread"

    def test_connection_failed(self):
        assert _extract_summary("❌ user@test.com: connection failed") == "error"

    def test_unknown_format(self):
        assert _extract_summary("Something unexpected happened") == "checked"


# ── _check_all_inboxes tests ─────────────────────────────────────────────────


GMAIL_ACCT = {
    "id": "gmail",
    "address": "user@gmail.com",
    "provider": "gmail",
}
OUTLOOK_ACCT = {
    "id": "outlook",
    "address": "user@outlook.com",
    "provider": "outlook",
}


@pytest.fixture
def mock_session():
    """Create a mock session with session_context dict."""
    session = MagicMock()
    session.session_context = {}
    return session


@pytest.fixture
def mock_session_mgr(mock_session):
    """Create a mock session manager."""
    mgr = MagicMock()
    return mgr


class TestCheckAllInboxes:
    @patch("familiar.skills.email.accounts.get_all_accounts", return_value=[])
    @patch("familiar.skills.email.skill._gmail_available", return_value=False)
    def test_no_accounts(self, _avail, _accts):
        result = _check_all_inboxes({})
        assert "No email accounts configured" in result

    @patch("familiar.skills.email.accounts.get_all_accounts", return_value=[OUTLOOK_ACCT])
    @patch("familiar.skills.email.skill._gmail_available", return_value=False)
    @patch("familiar.skills.email.skill._imap_check_inbox", return_value="📬 3 unread emails")
    def test_single_account_no_sentinel(self, _imap, _avail, _accts):
        """Single account returns plain text, not sentinel."""
        result = _check_all_inboxes({})
        assert not result.startswith(EMAIL_MENU_PREFIX)
        assert "3 unread emails" in result

    @patch("familiar.skills.email.accounts.get_all_accounts", return_value=[OUTLOOK_ACCT])
    @patch("familiar.skills.email.skill._gmail_available", return_value=True)
    @patch(
        "familiar.skills.email.skill._gmail_check_inbox",
        return_value="📬 2 unread emails (Gmail API):",
    )
    @patch("familiar.skills.email.skill._imap_check_inbox", return_value="📬 3 unread emails")
    def test_multi_account_returns_sentinel(
        self, _imap, _gmail, _avail, _accts, mock_session, mock_session_mgr
    ):
        """Multiple accounts with session returns EMAIL_MENU_PREFIX sentinel."""
        data = {
            "_context": {
                "session": mock_session,
                "session_manager": mock_session_mgr,
            }
        }
        result = _check_all_inboxes(data)
        assert result.startswith(EMAIL_MENU_PREFIX)
        # Verify session_context was populated
        email_menu = mock_session.session_context["email_menu"]
        assert "token" in email_menu
        assert "gmail_api" in email_menu["results"]
        assert OUTLOOK_ACCT["id"] in email_menu["results"]
        assert len(email_menu["summaries"]) == 2

    @patch("familiar.skills.email.accounts.get_all_accounts", return_value=[OUTLOOK_ACCT])
    @patch("familiar.skills.email.skill._gmail_available", return_value=True)
    @patch(
        "familiar.skills.email.skill._gmail_check_inbox",
        return_value="📬 2 unread emails (Gmail API):",
    )
    @patch("familiar.skills.email.skill._imap_check_inbox", return_value="📬 3 unread emails")
    def test_multi_account_no_session_fallback(self, _imap, _gmail, _avail, _accts):
        """Without session, falls back to concatenated text."""
        result = _check_all_inboxes({})
        assert not result.startswith(EMAIL_MENU_PREFIX)
        assert "Gmail API" in result
        assert "3 unread emails" in result

    @patch("familiar.skills.email.accounts.get_all_accounts", return_value=[OUTLOOK_ACCT])
    @patch("familiar.skills.email.skill._gmail_available", return_value=True)
    @patch(
        "familiar.skills.email.skill._gmail_check_inbox",
        return_value="📬 2 unread emails (Gmail API):",
    )
    @patch("familiar.skills.email.skill._imap_check_inbox", return_value="📬 3 unread emails")
    def test_session_manager_save_called(
        self, _imap, _gmail, _avail, _accts, mock_session, mock_session_mgr
    ):
        """Session manager save is called when sentinel is generated."""
        data = {
            "_context": {
                "session": mock_session,
                "session_manager": mock_session_mgr,
            }
        }
        _check_all_inboxes(data)
        mock_session_mgr.save_session.assert_called_once_with(mock_session)

    @patch("familiar.skills.email.accounts.get_all_accounts", return_value=[GMAIL_ACCT])
    @patch("familiar.skills.email.skill._gmail_available", return_value=True)
    @patch(
        "familiar.skills.email.skill._gmail_check_inbox",
        return_value="📬 2 unread emails (Gmail API):",
    )
    def test_gmail_api_skips_gmail_imap(self, _gmail, _avail, _accts):
        """When Gmail API succeeds, Gmail IMAP account is skipped (single account path)."""
        result = _check_all_inboxes({})
        assert "Gmail API" in result
        assert not result.startswith(EMAIL_MENU_PREFIX)
