import os
import sys
import tempfile

_fd, _TMP = tempfile.mkstemp(suffix=".db")
os.close(_fd)
os.unlink(_TMP)
os.environ["AGENT_OFFICE_DB_PATH"] = _TMP

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


import pytest
from unittest.mock import AsyncMock, patch


@pytest.fixture(autouse=True)
def _init_db():
    import gc
    gc.collect()
    if os.path.exists(_TMP):
        os.remove(_TMP)
    from app.db import init_db
    init_db()
    yield
    gc.collect()


@pytest.mark.asyncio
async def test_poll_notifies_once_per_state():
    from app.agents.youtube_publisher import YoutubePublisherAgent

    pipelines = [{
        "id": 1,
        "state": "cover_pending",
        "cover_url": "/x.jpg",
        "track_title": "Test",
        "feedback_count_per_step": {},
    }]
    with patch(
        "app.agents.youtube_publisher.service_proxy.list_active_pipelines",
        new=AsyncMock(return_value=pipelines),
    ), patch(
        "app.agents.youtube_publisher.service_proxy.list_failed_pipelines",
        new=AsyncMock(return_value=[]),
    ), patch(
        "app.agents.youtube_publisher.send_raw",
        new=AsyncMock(return_value={"ok": True, "message_id": 99}),
    ) as mock_send, patch(
        "app.agents.youtube_publisher.service_proxy.save_pipeline_telegram_msg",
        new=AsyncMock(),
    ):
        a = YoutubePublisherAgent()
        await a.poll_state_changes()
        await a.poll_state_changes()  # 같은 상태 — 두 번째는 알림 안 함
        assert mock_send.call_count == 1


@pytest.mark.asyncio
async def test_poll_renotifies_on_reject_regen(monkeypatch):
    from app.agents.youtube_publisher import YoutubePublisherAgent

    pipelines_v1 = [{"id": 1, "state": "cover_pending", "cover_url": "/x.jpg",
                      "track_title": "Test", "feedback_count_per_step": {}}]
    pipelines_v2 = [{"id": 1, "state": "cover_pending", "cover_url": "/x2.jpg",
                      "track_title": "Test", "feedback_count_per_step": {"cover": 1}}]
    list_mock = AsyncMock(side_effect=[pipelines_v1, pipelines_v2])
    with patch("app.agents.youtube_publisher.service_proxy.list_active_pipelines", list_mock), \
         patch("app.agents.youtube_publisher.service_proxy.list_failed_pipelines",
                new=AsyncMock(return_value=[])), \
         patch("app.agents.youtube_publisher.send_raw",
                new=AsyncMock(return_value={"ok": True, "message_id": 99})), \
         patch("app.agents.youtube_publisher.service_proxy.save_pipeline_telegram_msg",
                new=AsyncMock()):
        a = YoutubePublisherAgent()
        await a.poll_state_changes()  # 1st: notify
        await a.poll_state_changes()  # 2nd: feedback count differs → notify again
        from app.agents.youtube_publisher import send_raw as sr
        assert sr.call_count == 2


@pytest.mark.asyncio
async def test_on_telegram_reply_approve_calls_feedback():
    from app.agents.youtube_publisher import YoutubePublisherAgent

    with patch(
        "app.agents.youtube_publisher.service_proxy.post_pipeline_feedback",
        new=AsyncMock(),
    ) as mock_fb, patch(
        "app.agents.youtube_publisher.send_raw",
        new=AsyncMock(return_value={"ok": True, "message_id": 1}),
    ):
        a = YoutubePublisherAgent()
        await a.on_telegram_reply(pipeline_id=42, step="cover", user_text="승인")
        mock_fb.assert_called_once_with(42, "cover", "approve", None)


@pytest.mark.asyncio
async def test_on_telegram_reply_reject_with_feedback():
    from app.agents.youtube_publisher import YoutubePublisherAgent

    with patch(
        "app.agents.youtube_publisher.service_proxy.post_pipeline_feedback",
        new=AsyncMock(),
    ) as mock_fb, patch(
        "app.agents.youtube_publisher.send_raw",
        new=AsyncMock(return_value={"ok": True, "message_id": 1}),
    ):
        a = YoutubePublisherAgent()
        await a.on_telegram_reply(pipeline_id=43, step="meta", user_text="반려, 제목 짧게")
        args = mock_fb.call_args[0]
        assert args[0] == 43
        assert args[1] == "meta"
        assert args[2] == "reject"
        assert "제목 짧게" in (args[3] or "")


@pytest.mark.asyncio
async def test_on_telegram_reply_unclear_asks_again():
    from app.agents.youtube_publisher import YoutubePublisherAgent

    sent = []

    async def mock_send(text=None, **kw):
        sent.append(text)
        return {"ok": True, "message_id": 1}

    with patch(
        "app.agents.youtube_publisher.send_raw",
        new=mock_send,
    ), patch(
        "app.agents.youtube_publisher.classify_intent.classify",
        return_value=("unclear", None),
    ):
        a = YoutubePublisherAgent()
        await a.on_telegram_reply(pipeline_id=44, step="cover", user_text="huh?")
        assert any("다시 입력" in (s or "") for s in sent)
