"""
Tests for:
1. Super Admin email update to alok.chaudhary2001@gmail.com
2. End Chat conversation transcript email generation & dispatch
"""
import pytest
from unittest.mock import patch, MagicMock
from app.database import get_database
from app.config import settings
from app.repositories.session_repository import create_session
from app.repositories.conversation_repository import get_or_create_conversation
from app.repositories.message_repository import create_message
from app.repositories.agent_repository import get_agent_by_email
from app.services.presence import add_active_session
from app.services.email_service import (
    build_transcript_email_content,
    send_conversation_transcript_email,
    _format_time_str
)


@pytest.mark.anyio
async def test_super_admin_email_is_updated_in_db(client):
    """
    Verify that the Super Admin seed has email alok.chaudhary2001@gmail.com
    and retains its ADMIN role.
    """
    from app.database import InMemoryDatabase
    seeded_db = InMemoryDatabase(seed_default=True)
    admin = await seeded_db["agents"].find_one({"role": "ADMIN"})
    assert admin is not None
    assert admin["email"] == "alok.chaudhary2001@gmail.com"
    assert admin["role"] == "ADMIN"
    assert admin["status"] == "ACTIVE"


@pytest.mark.anyio
async def test_transcript_email_content_formatting():
    """
    Verify that build_transcript_email_content generates the required metadata
    and chronological message list.
    """
    from datetime import datetime, timezone

    session = {
        "sessionId": "sess_test_12345",
        "siteId": "site_demo_abc",
        "ipAddress": "198.51.100.42",
        "country": "India",
        "assignedAgentId": "agent_alpha_999",
        "createdAt": datetime(2026, 8, 31, 10, 0, 0, tzinfo=timezone.utc)
    }
    agent_info = {
        "agentId": "agent_alpha_999",
        "name": "Alok Chaudhary",
        "email": "alok.chaudhary2001@gmail.com"
    }
    messages = [
        {
            "messageId": "msg_1",
            "role": "user",
            "content": "Hello, I need assistance with my order.",
            "createdAt": datetime(2026, 8, 31, 10, 1, 15, tzinfo=timezone.utc)
        },
        {
            "messageId": "msg_2",
            "role": "agent",
            "content": "Hello! I am happy to help you with that.",
            "createdAt": datetime(2026, 8, 31, 10, 1, 45, tzinfo=timezone.utc)
        },
        {
            "messageId": "msg_3",
            "role": "system",
            "content": "Video call ended.",
            "createdAt": datetime(2026, 8, 31, 10, 5, 0, tzinfo=timezone.utc)
        }
    ]

    text_body, html_body = build_transcript_email_content(
        session=session,
        conversation={"conversationId": "conv_test_1"},
        messages=messages,
        agent_info=agent_info,
        ended_by="agent",
        ended_at=datetime(2026, 8, 31, 10, 6, 0, tzinfo=timezone.utc)
    )

    # Verify session details in plain text
    assert "Chat Session Details" in text_body
    assert "Session ID: sess_test_12345" in text_body
    assert "Site ID: site_demo_abc" in text_body
    assert "Visitor IP: 198.51.100.42" in text_body
    assert "Country: India" in text_body
    assert "Assigned Agent: Alok Chaudhary" in text_body
    assert "Agent Email: alok.chaudhary2001@gmail.com" in text_body
    assert "Chat Started At: 2026-08-31 10:00:00 UTC" in text_body
    assert "Chat Ended At: 2026-08-31 10:06:00 UTC" in text_body
    assert "Ended By: agent" in text_body

    # Verify conversation transcript in chronological order
    assert "Conversation Transcript" in text_body
    assert "[10:01:15 UTC] Visitor:\nHello, I need assistance with my order." in text_body
    assert "[10:01:45 UTC] Agent (Alok Chaudhary):\nHello! I am happy to help you with that." in text_body
    assert "[10:05:00 UTC] System:\nVideo call ended." in text_body

    # Verify HTML version
    assert "sess_test_12345" in html_body
    assert "alok.chaudhary2001@gmail.com" in html_body
    assert "Hello, I need assistance with my order." in html_body


@pytest.mark.anyio
async def test_end_chat_triggers_transcript_email(client):
    """
    End Chat HTTP endpoint should load complete conversation and dispatch email to
    alok.chaudhary2001@gmail.com with subject 'Chat Conversation — <sessionId>'.
    """
    db = get_database()
    sess = await create_session(db, site_id="site_demo_123")
    sid = sess["sessionId"]

    conv = await get_or_create_conversation(db, sid, "site_demo_123")
    cid = conv["conversationId"]

    # Insert messages in DB
    await create_message(db, cid, sid, "user", "Visitor initial query")
    await create_message(db, cid, sid, "agent", "Agent first response", agent_id="agent_1")
    await create_message(db, cid, sid, "user", "Visitor follow-up query")

    from unittest.mock import AsyncMock
    mock_ws = AsyncMock()
    add_active_session(sid, "site_demo_123", mock_ws, status_val="IN_CHAT", assigned_agent_id="agent_1")

    with patch("app.services.email_service._send_smtp_sync") as mock_smtp:
        mock_smtp.return_value = True

        resp = client.post("/api/v1/handoff/end", json={
            "sessionId": sid,
            "endedBy": "agent"
        })
        assert resp.status_code == 200
        assert resp.json()["status"] == "ENDED"

        # Verify SMTP send worker was called
        mock_smtp.assert_called_once()
        call_kwargs = mock_smtp.call_args.kwargs
        assert call_kwargs["recipient"] == "alok.chaudhary2001@gmail.com"
        assert call_kwargs["subject"] == f"Chat Conversation — {sid}"
        assert "Visitor initial query" in call_kwargs["text_content"]
        assert "Agent first response" in call_kwargs["text_content"]
        assert "Visitor follow-up query" in call_kwargs["text_content"]


@pytest.mark.anyio
async def test_duplicate_end_chat_does_not_send_duplicate_emails(client):
    """
    Subsequent calls to end_chat for the same session should not re-send the email.
    """
    db = get_database()
    sess = await create_session(db, site_id="site_demo_123")
    sid = sess["sessionId"]
    conv = await get_or_create_conversation(db, sid, "site_demo_123")
    cid = conv["conversationId"]

    await create_message(db, cid, sid, "user", "Test message")

    from unittest.mock import AsyncMock
    mock_ws = AsyncMock()
    add_active_session(sid, "site_demo_123", mock_ws, status_val="IN_CHAT", assigned_agent_id="agent_1")

    with patch("app.services.email_service._send_smtp_sync") as mock_smtp:
        mock_smtp.return_value = True

        # First End Chat
        resp1 = client.post("/api/v1/handoff/end", json={"sessionId": sid, "endedBy": "agent"})
        assert resp1.status_code == 200
        assert mock_smtp.call_count == 1

        # Second End Chat (duplicate trigger)
        resp2 = client.post("/api/v1/handoff/end", json={"sessionId": sid, "endedBy": "agent"})
        assert resp2.status_code == 200
        # Call count should remain 1 (no duplicate send)
        assert mock_smtp.call_count == 1


@pytest.mark.anyio
async def test_email_failure_does_not_break_end_chat(client):
    """
    If the email dispatch raises an unhandled exception or SMTP fails,
    End Chat must still succeed cleanly with status 200 and mark chat as ENDED.
    """
    db = get_database()
    sess = await create_session(db, site_id="site_demo_123")
    sid = sess["sessionId"]
    conv = await get_or_create_conversation(db, sid, "site_demo_123")
    cid = conv["conversationId"]
    await create_message(db, cid, sid, "user", "Hello before error")

    from unittest.mock import AsyncMock
    mock_ws = AsyncMock()
    add_active_session(sid, "site_demo_123", mock_ws, status_val="IN_CHAT")

    with patch("app.services.email_service._send_smtp_sync", side_effect=Exception("SMTP server connection timeout")):
        resp = client.post("/api/v1/handoff/end", json={"sessionId": sid, "endedBy": "visitor"})
        assert resp.status_code == 200
        assert resp.json()["status"] == "ENDED"

    # Verify session is still marked ENDED in database
    updated_sess = await db["sessions"].find_one({"sessionId": sid})
    assert updated_sess["status"] == "ENDED"


@pytest.mark.anyio
async def test_video_call_termination_on_end_chat_preserved(client):
    """
    Verifies that video calls are cleanly terminated when end_chat is triggered.
    """
    db = get_database()
    sess = await create_session(db, site_id="site_demo_123")
    sid = sess["sessionId"]

    from unittest.mock import AsyncMock
    mock_ws = AsyncMock()
    add_active_session(sid, "site_demo_123", mock_ws, status_val="IN_CHAT")

    from app.services.video_signaling import active_calls, set_call_state
    set_call_state(sid, "CONNECTED", "agent_1")
    assert sid in active_calls

    with patch("app.services.email_service._send_smtp_sync", return_value=True):
        resp = client.post("/api/v1/handoff/end", json={"sessionId": sid, "endedBy": "agent"})
        assert resp.status_code == 200

    # Video call should be removed/terminated
    assert sid not in active_calls
