"""
notification.py のテスト

通知機能（Slack、メール）のテストを行います。
"""

import pytest
from unittest.mock import patch, MagicMock
from komon.notification import send_slack_alert, send_email_alert, send_discord_alert, send_teams_alert


class TestSendSlackAlert:
    """Slack通知のテスト"""
    
    @patch('komon.notification.requests.post')
    def test_send_slack_success(self, mock_post):
        """Slack通知が成功する場合"""
        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_post.return_value = mock_response
        
        result = send_slack_alert(
            message="テストメッセージ",
            webhook_url="https://hooks.slack.com/services/TEST"
        )
        
        assert result is True
        mock_post.assert_called_once()
        call_args = mock_post.call_args
        assert call_args[0][0] == "https://hooks.slack.com/services/TEST"
        assert call_args[1]['json'] == {"text": "テストメッセージ"}
    
    @patch('komon.notification.requests.post')
    def test_send_slack_failure_status_code(self, mock_post):
        """Slack通知が失敗する場合（ステータスコードエラー）"""
        mock_response = MagicMock()
        mock_response.status_code = 404
        mock_post.return_value = mock_response
        
        result = send_slack_alert(
            message="テストメッセージ",
            webhook_url="https://hooks.slack.com/services/INVALID"
        )
        
        assert result is False
    
    @patch('komon.notification.requests.post')
    def test_send_slack_exception(self, mock_post):
        """Slack通知で例外が発生する場合"""
        mock_post.side_effect = Exception("Network error")
        
        result = send_slack_alert(
            message="テストメッセージ",
            webhook_url="https://hooks.slack.com/services/TEST"
        )
        
        assert result is False
    
    @patch('komon.notification.requests.post')
    def test_send_slack_timeout(self, mock_post):
        """Slack通知でタイムアウトが発生する場合"""
        import requests
        mock_post.side_effect = requests.Timeout("Request timeout")
        
        result = send_slack_alert(
            message="テストメッセージ",
            webhook_url="https://hooks.slack.com/services/TEST"
        )
        
        assert result is False
    
    @patch('komon.notification.requests.post')
    @patch('komon.notification.os.getenv')
    def test_send_slack_with_env_webhook(self, mock_getenv, mock_post):
        """環境変数からWebhook URLを読み込む場合"""
        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_post.return_value = mock_response
        mock_getenv.return_value = "https://hooks.slack.com/services/REAL_WEBHOOK"
        
        result = send_slack_alert(
            message="テストメッセージ",
            webhook_url="env:KOMON_SLACK_WEBHOOK"
        )
        
        assert result is True
        mock_getenv.assert_called_once_with("KOMON_SLACK_WEBHOOK", "")
        call_args = mock_post.call_args
        assert call_args[0][0] == "https://hooks.slack.com/services/REAL_WEBHOOK"
    
    @patch('komon.notification.os.getenv')
    def test_send_slack_with_missing_env_webhook(self, mock_getenv):
        """環境変数が設定されていない場合"""
        mock_getenv.return_value = ""
        
        result = send_slack_alert(
            message="テストメッセージ",
            webhook_url="env:KOMON_SLACK_WEBHOOK"
        )
        
        assert result is False
        mock_getenv.assert_called_once_with("KOMON_SLACK_WEBHOOK", "")


class TestSendDiscordAlert:
    """Discord通知のテスト"""
    
    @patch('komon.notification.requests.post')
    def test_send_discord_success(self, mock_post):
        """Discord通知が成功する場合"""
        mock_response = MagicMock()
        mock_response.status_code = 204  # Discordは204を返す
        mock_post.return_value = mock_response
        
        result = send_discord_alert(
            message="テストメッセージ",
            webhook_url="https://discord.com/api/webhooks/TEST"
        )
        
        assert result is True
        mock_post.assert_called_once()
        call_args = mock_post.call_args
        assert call_args[0][0] == "https://discord.com/api/webhooks/TEST"
        assert call_args[1]['json'] == {"content": "テストメッセージ"}
    
    @patch('komon.notification.requests.post')
    def test_send_discord_failure_status_code(self, mock_post):
        """Discord通知が失敗する場合（ステータスコードエラー）"""
        mock_response = MagicMock()
        mock_response.status_code = 404
        mock_post.return_value = mock_response
        
        result = send_discord_alert(
            message="テストメッセージ",
            webhook_url="https://discord.com/api/webhooks/INVALID"
        )
        
        assert result is False
    
    @patch('komon.notification.requests.post')
    def test_send_discord_exception(self, mock_post):
        """Discord通知で例外が発生する場合"""
        mock_post.side_effect = Exception("Network error")
        
        result = send_discord_alert(
            message="テストメッセージ",
            webhook_url="https://discord.com/api/webhooks/TEST"
        )
        
        assert result is False
    
    @patch('komon.notification.requests.post')
    @patch('komon.notification.os.getenv')
    def test_send_discord_with_env_webhook(self, mock_getenv, mock_post):
        """環境変数からWebhook URLを読み込む場合"""
        mock_response = MagicMock()
        mock_response.status_code = 204
        mock_post.return_value = mock_response
        mock_getenv.return_value = "https://discord.com/api/webhooks/REAL_WEBHOOK"
        
        result = send_discord_alert(
            message="テストメッセージ",
            webhook_url="env:KOMON_DISCORD_WEBHOOK"
        )
        
        assert result is True
        mock_getenv.assert_called_once_with("KOMON_DISCORD_WEBHOOK", "")
        call_args = mock_post.call_args
        assert call_args[0][0] == "https://discord.com/api/webhooks/REAL_WEBHOOK"
    
    @patch('komon.notification.os.getenv')
    def test_send_discord_with_missing_env_webhook(self, mock_getenv):
        """環境変数が設定されていない場合"""
        mock_getenv.return_value = ""
        
        result = send_discord_alert(
            message="テストメッセージ",
            webhook_url="env:KOMON_DISCORD_WEBHOOK"
        )
        
        assert result is False
        mock_getenv.assert_called_once_with("KOMON_DISCORD_WEBHOOK", "")


class TestSendTeamsAlert:
    """Teams通知のテスト"""
    
    @patch('komon.notification.requests.post')
    def test_send_teams_success(self, mock_post):
        """Teams通知が成功する場合"""
        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_post.return_value = mock_response
        
        result = send_teams_alert(
            message="テストメッセージ",
            webhook_url="https://outlook.office.com/webhook/TEST"
        )
        
        assert result is True
        mock_post.assert_called_once()
        call_args = mock_post.call_args
        assert call_args[0][0] == "https://outlook.office.com/webhook/TEST"
        assert call_args[1]['json'] == {"text": "テストメッセージ"}
    
    @patch('komon.notification.requests.post')
    def test_send_teams_failure_status_code(self, mock_post):
        """Teams通知が失敗する場合（ステータスコードエラー）"""
        mock_response = MagicMock()
        mock_response.status_code = 404
        mock_post.return_value = mock_response
        
        result = send_teams_alert(
            message="テストメッセージ",
            webhook_url="https://outlook.office.com/webhook/INVALID"
        )
        
        assert result is False
    
    @patch('komon.notification.requests.post')
    def test_send_teams_exception(self, mock_post):
        """Teams通知で例外が発生する場合"""
        mock_post.side_effect = Exception("Network error")
        
        result = send_teams_alert(
            message="テストメッセージ",
            webhook_url="https://outlook.office.com/webhook/TEST"
        )
        
        assert result is False
    
    @patch('komon.notification.requests.post')
    @patch('komon.notification.os.getenv')
    def test_send_teams_with_env_webhook(self, mock_getenv, mock_post):
        """環境変数からWebhook URLを読み込む場合"""
        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_post.return_value = mock_response
        mock_getenv.return_value = "https://outlook.office.com/webhook/REAL_WEBHOOK"
        
        result = send_teams_alert(
            message="テストメッセージ",
            webhook_url="env:KOMON_TEAMS_WEBHOOK"
        )
        
        assert result is True
        mock_getenv.assert_called_once_with("KOMON_TEAMS_WEBHOOK", "")
        call_args = mock_post.call_args
        assert call_args[0][0] == "https://outlook.office.com/webhook/REAL_WEBHOOK"
    
    @patch('komon.notification.os.getenv')
    def test_send_teams_with_missing_env_webhook(self, mock_getenv):
        """環境変数が設定されていない場合"""
        mock_getenv.return_value = ""
        
        result = send_teams_alert(
            message="テストメッセージ",
            webhook_url="env:KOMON_TEAMS_WEBHOOK"
        )
        
        assert result is False
        mock_getenv.assert_called_once_with("KOMON_TEAMS_WEBHOOK", "")


class TestSendEmailAlert:
    """メール通知のテスト"""
    
    @patch('komon.notification.smtplib.SMTP')
    def test_send_email_success(self, mock_smtp):
        """メール通知が成功する場合"""
        mock_server = MagicMock()
        mock_smtp.return_value.__enter__.return_value = mock_server
        
        email_config = {
            "smtp_server": "smtp.example.com",
            "smtp_port": 587,
            "from": "komon@example.com",
            "to": "admin@example.com",
            "username": "user",
            "password": "pass"
        }
        
        result = send_email_alert("テストメッセージ", email_config)
        
        assert result is True
        mock_server.starttls.assert_called_once()
        mock_server.login.assert_called_once_with("user", "pass")
        mock_server.send_message.assert_called_once()
    
    @patch('komon.notification.smtplib.SMTP')
    def test_send_email_without_auth(self, mock_smtp):
        """認証なしでメール通知が成功する場合"""
        mock_server = MagicMock()
        mock_smtp.return_value.__enter__.return_value = mock_server
        
        email_config = {
            "smtp_server": "smtp.example.com",
            "smtp_port": 25,
            "from": "komon@example.com",
            "to": "admin@example.com",
            "use_tls": False
        }
        
        result = send_email_alert("テストメッセージ", email_config)
        
        assert result is True
        mock_server.starttls.assert_not_called()
        mock_server.login.assert_not_called()
        mock_server.send_message.assert_called_once()
    
    @patch('komon.notification.smtplib.SMTP')
    @patch('komon.notification.os.getenv')
    def test_send_email_with_env_password(self, mock_getenv, mock_smtp):
        """環境変数からパスワードを読み込む場合"""
        mock_server = MagicMock()
        mock_smtp.return_value.__enter__.return_value = mock_server
        mock_getenv.return_value = "secret_password"
        
        email_config = {
            "smtp_server": "smtp.example.com",
            "smtp_port": 587,
            "from": "komon@example.com",
            "to": "admin@example.com",
            "username": "user",
            "password": "env:SMTP_PASSWORD"
        }
        
        result = send_email_alert("テストメッセージ", email_config)
        
        assert result is True
        mock_getenv.assert_called_once_with("SMTP_PASSWORD", "")
        mock_server.login.assert_called_once_with("user", "secret_password")
    
    @patch('komon.notification.smtplib.SMTP')
    def test_send_email_exception(self, mock_smtp):
        """メール送信で例外が発生する場合"""
        mock_smtp.side_effect = Exception("SMTP connection failed")
        
        email_config = {
            "smtp_server": "smtp.example.com",
            "smtp_port": 587,
            "from": "komon@example.com",
            "to": "admin@example.com"
        }
        
        result = send_email_alert("テストメッセージ", email_config)
        
        assert result is False
    
    @patch('komon.notification.smtplib.SMTP')
    def test_send_email_default_port(self, mock_smtp):
        """デフォルトポート（587）が使用される場合"""
        mock_server = MagicMock()
        mock_smtp.return_value.__enter__.return_value = mock_server
        
        email_config = {
            "smtp_server": "smtp.example.com",
            "from": "komon@example.com",
            "to": "admin@example.com"
        }
        
        result = send_email_alert("テストメッセージ", email_config)
        
        assert result is True
        mock_smtp.assert_called_once_with("smtp.example.com", 587)
