"""Tests for Telegram settings endpoints and notify toggle hot-reload."""

from unittest.mock import AsyncMock, MagicMock, patch

import pytest
from fastapi import HTTPException

from server.config import settings


@pytest.mark.asyncio
async def test_telegram_test_400_when_token_missing():
    from server.api.settings import telegram_test_send

    settings.TELEGRAM_BOT_TOKEN = ""
    settings.TELEGRAM_CHAT_ID = ""
    admin = MagicMock()

    with pytest.raises(HTTPException) as exc:
        await telegram_test_send(admin=admin)
    assert exc.value.status_code == 400
    assert "TELEGRAM_BOT_TOKEN" in exc.value.detail


@pytest.mark.asyncio
async def test_telegram_test_400_when_chat_id_missing():
    from server.api.settings import telegram_test_send

    settings.TELEGRAM_BOT_TOKEN = "123456:ABC"
    settings.TELEGRAM_CHAT_ID = ""
    admin = MagicMock()

    with pytest.raises(HTTPException) as exc:
        await telegram_test_send(admin=admin)
    assert exc.value.status_code == 400
    assert "TELEGRAM_CHAT_ID" in exc.value.detail


@pytest.mark.asyncio
async def test_telegram_test_surfaces_api_error():
    from server.api.settings import telegram_test_send

    settings.TELEGRAM_BOT_TOKEN = "123456:ABC"
    settings.TELEGRAM_CHAT_ID = "999"
    admin = MagicMock()

    mock_resp = MagicMock()
    mock_resp.status_code = 400
    mock_resp.json.return_value = {"ok": False, "description": "Bad Request: chat not found"}

    mock_client = AsyncMock()
    mock_client.__aenter__.return_value = mock_client
    mock_client.__aexit__.return_value = None
    mock_client.post = AsyncMock(return_value=mock_resp)

    with patch("httpx.AsyncClient", return_value=mock_client):
        with pytest.raises(HTTPException) as exc:
            await telegram_test_send(admin=admin)

    assert exc.value.status_code == 502
    assert "chat not found" in exc.value.detail


@pytest.mark.asyncio
async def test_telegram_chats_surfaces_api_error_when_ok_false():
    from server.api.settings import telegram_get_chats

    settings.TELEGRAM_BOT_TOKEN = "123456:ABC"
    admin = MagicMock()

    wh_resp = MagicMock()
    wh_resp.status_code = 200
    wh_resp.json.return_value = {"ok": True, "result": {"url": ""}}

    updates_resp = MagicMock()
    updates_resp.status_code = 200
    updates_resp.json.return_value = {"ok": False, "description": "Unauthorized"}

    mock_client = AsyncMock()
    mock_client.__aenter__.return_value = mock_client
    mock_client.__aexit__.return_value = None
    mock_client.get = AsyncMock(side_effect=[wh_resp, updates_resp])
    mock_client.post = AsyncMock()

    with patch("httpx.AsyncClient", return_value=mock_client):
        with pytest.raises(HTTPException) as exc:
            await telegram_get_chats(admin=admin)

    assert exc.value.status_code == 502
    assert "Unauthorized" in exc.value.detail


@pytest.mark.asyncio
async def test_telegram_chats_deletes_webhook_before_get_updates():
    from server.api.settings import telegram_get_chats

    settings.TELEGRAM_BOT_TOKEN = "123456:ABC"
    admin = MagicMock()

    wh_resp = MagicMock()
    wh_resp.status_code = 200
    wh_resp.json.return_value = {"ok": True, "result": {"url": "https://example.com/hook"}}

    del_resp = MagicMock()
    del_resp.json.return_value = {"ok": True}

    updates_resp = MagicMock()
    updates_resp.status_code = 200
    updates_resp.json.return_value = {
        "ok": True,
        "result": [
            {
                "message": {
                    "chat": {"id": 42, "type": "private", "first_name": "Test"},
                },
            },
        ],
    }

    mock_client = AsyncMock()
    mock_client.__aenter__.return_value = mock_client
    mock_client.__aexit__.return_value = None
    mock_client.get = AsyncMock(side_effect=[wh_resp, updates_resp])
    mock_client.post = AsyncMock(return_value=del_resp)

    with patch("httpx.AsyncClient", return_value=mock_client):
        result = await telegram_get_chats(admin=admin)

    assert result["count"] == 1
    assert result["chats"][0]["id"] == 42
    mock_client.post.assert_called_once()
    call_args = mock_client.post.call_args
    assert "deleteWebhook" in call_args[0][0]
    assert call_args[1]["params"]["drop_pending_updates"] == "false"


@pytest.mark.asyncio
async def test_telegram_chats_includes_my_chat_member_supergroup():
    from server.api.settings import _extract_chats_from_telegram_updates

    updates = [
        {
            "my_chat_member": {
                "chat": {"id": -1001234567890, "title": "Ops Group", "type": "supergroup"},
            },
        },
        {
            "message": {
                "chat": {"id": 42, "type": "private", "first_name": "Alice"},
            },
        },
    ]
    chats = _extract_chats_from_telegram_updates(updates)
    assert len(chats) == 2
    assert chats[0]["id"] == -1001234567890
    assert chats[0]["type"] == "supergroup"
    assert chats[0]["title"] == "Ops Group"
    assert chats[1]["id"] == 42


@pytest.mark.asyncio
async def test_telegram_chats_includes_edited_message_and_callback():
    from server.api.settings import _extract_chats_from_telegram_updates

    updates = [
        {
            "edited_message": {
                "chat": {"id": -10099, "title": "Alert Room", "type": "group"},
            },
        },
        {
            "callback_query": {
                "message": {
                    "chat": {"id": -10088, "title": "Channel", "type": "channel"},
                },
            },
        },
    ]
    chats = _extract_chats_from_telegram_updates(updates)
    ids = {c["id"] for c in chats}
    assert -10099 in ids
    assert -10088 in ids


@pytest.mark.asyncio
async def test_notify_toggle_put_hot_reload():
    from server.api.schemas import SettingUpdatePayload
    from server.api.settings import set_setting
    from server.domain.models import Setting

    settings.NOTIFY_ALERT_CPU = "true"
    admin = MagicMock(username="admin")
    request = MagicMock()
    request.client.host = "127.0.0.1"
    db = MagicMock()

    mock_setting = Setting(key="notify_alert_cpu", value="false")

    with patch("server.api.settings.SettingRepositoryImpl") as repo_cls, patch(
        "server.api.settings.AuditLogRepositoryImpl"
    ) as audit_cls:
        repo = repo_cls.return_value
        repo.set = AsyncMock(return_value=mock_setting)
        audit_cls.return_value.create = AsyncMock()

        await set_setting(
            "notify_alert_cpu",
            SettingUpdatePayload(value="false"),
            request,
            admin,
            db,
        )

    assert settings.NOTIFY_ALERT_CPU == "false"
