"""
utils.discord_webhook 단위 테스트.

네트워크 호출은 mock — 실제 Discord API는 절대 건드리지 않음.
"""
import os
import sys
from unittest.mock import patch, MagicMock

import pytest

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from utils.discord_webhook import (
    send, send_test, send_clock_in, send_clock_out, send_health_warning,
    USER_AGENT, COLOR_GREEN, COLOR_BLUE,
)


class TestSendInputValidation:
    def test_empty_url_returns_false(self):
        assert send('', 'title', 'desc') is False

    def test_non_https_url_returns_false(self):
        # 보안상 http:// 거부
        assert send('http://example.com/webhook', 'title', 'desc') is False
        assert send('ftp://example.com', 'title', 'desc') is False

    def test_none_url_returns_false(self):
        assert send(None, 'title', 'desc') is False


class TestSendNetwork:
    @patch('utils.discord_webhook.urllib.request.urlopen')
    def test_success(self, mock_urlopen):
        resp = MagicMock()
        resp.status = 204
        resp.__enter__.return_value = resp
        resp.__exit__.return_value = False
        mock_urlopen.return_value = resp

        ok = send('https://discord.com/api/webhooks/123456789012345678/' + 'a' * 60, 'title', 'desc')
        assert ok is True

        # User-Agent 헤더가 브라우저로 위장되어 있는지 (Cloudflare 우회)
        req = mock_urlopen.call_args[0][0]
        assert req.headers.get('User-agent') == USER_AGENT
        assert 'Mozilla' in USER_AGENT  # 봇으로 인식 안 되도록

    @patch('utils.discord_webhook.urllib.request.urlopen')
    def test_4xx_returns_false(self, mock_urlopen):
        resp = MagicMock()
        resp.status = 403
        resp.__enter__.return_value = resp
        resp.__exit__.return_value = False
        mock_urlopen.return_value = resp

        assert send('https://discord.com/api/webhooks/123456789012345678/' + 'b' * 60, 't', 'd') is False

    @patch('utils.discord_webhook.urllib.request.urlopen')
    def test_network_error_returns_false(self, mock_urlopen):
        import urllib.error
        mock_urlopen.side_effect = urllib.error.URLError('boom')
        assert send('https://discord.com/api/webhooks/123456789012345678/' + 'b' * 60, 't', 'd') is False

    @patch('utils.discord_webhook.urllib.request.urlopen')
    def test_timeout_returns_false(self, mock_urlopen):
        mock_urlopen.side_effect = TimeoutError('slow')
        assert send('https://discord.com/api/webhooks/123456789012345678/' + 'b' * 60, 't', 'd') is False


class TestPayloadShape:
    @patch('utils.discord_webhook.urllib.request.urlopen')
    def test_payload_contains_embed(self, mock_urlopen):
        import json as _json
        resp = MagicMock()
        resp.status = 204
        resp.__enter__.return_value = resp
        resp.__exit__.return_value = False
        mock_urlopen.return_value = resp

        send('https://discord.com/api/webhooks/123456789012345678/' + 'b' * 60, 'TITLE', 'DESC',
             color=COLOR_GREEN, fields=[{"name": "f", "value": "v"}])
        req = mock_urlopen.call_args[0][0]
        body = _json.loads(req.data.decode('utf-8'))
        assert 'embeds' in body
        assert body['embeds'][0]['title'] == 'TITLE'
        assert body['embeds'][0]['description'] == 'DESC'
        assert body['embeds'][0]['color'] == COLOR_GREEN
        assert body['embeds'][0]['fields'] == [{"name": "f", "value": "v"}]


class TestHelpers:
    @patch('utils.discord_webhook.send')
    def test_send_test(self, mock_send):
        mock_send.return_value = True
        send_test('https://discord.com/x')
        assert mock_send.called
        kwargs = mock_send.call_args.kwargs
        assert kwargs.get('color') == COLOR_GREEN

    @patch('utils.discord_webhook.send')
    def test_send_clock_in(self, mock_send):
        send_clock_in('https://discord.com/x', '09:00')
        kwargs = mock_send.call_args.kwargs
        assert '09:00' in kwargs.get('description', '')

    @patch('utils.discord_webhook.send')
    def test_send_clock_out_no_overtime(self, mock_send):
        send_clock_out('https://discord.com/x', '18:00', 8.0, 0, 0)
        kwargs = mock_send.call_args.kwargs
        # 연장 없음 → 파란색
        assert kwargs.get('color') == COLOR_BLUE
        # 필드: 총 근무시간만
        assert len(kwargs.get('fields', [])) == 1

    @patch('utils.discord_webhook.send')
    def test_send_clock_out_with_overtime(self, mock_send):
        send_clock_out('https://discord.com/x', '19:30', 9.5, 90, 90)
        kwargs = mock_send.call_args.kwargs
        # 연장 있음 → 노란색
        assert kwargs.get('color') != COLOR_BLUE
        assert len(kwargs.get('fields', [])) == 2

    @patch('utils.discord_webhook.send')
    def test_send_health_warning(self, mock_send):
        send_health_warning('https://discord.com/x', 4.5)
        kwargs = mock_send.call_args.kwargs
        assert '4.5' in kwargs.get('description', '')
