import uuid
from fastapi import status
from app.services.presence import active_sessions

def test_active_sessions_snapshot_and_flow(client):
    # 1. Register a tenant
    domain = f"demo-{uuid.uuid4().hex[:6]}.com"
    reg_resp = client.post("/api/v1/tenant/register", json={
        "domain": domain,
        "name": "Live Chat Demo Store"
    })
    assert reg_resp.status_code == status.HTTP_201_CREATED
    site_id = reg_resp.json()["siteId"]

    # 2. Init session with logged-in user
    headers = {"Origin": f"http://{domain}"}
    init_resp = client.post("/api/v1/session/init", json={
        "siteId": site_id,
        "user": {
            "id": "usr_demo_888",
            "name": "Alice Visitor",
            "email": "alice@example.com"
        }
    }, headers=headers)
    assert init_resp.status_code == status.HTTP_201_CREATED
    session_id = init_resp.json()["sessionId"]

    # 3. Connect visitor to WebSocket presence and run active session flow
    with client.websocket_connect(f"/ws/session/{session_id}") as ws:
        assert session_id in active_sessions
        assert active_sessions[session_id]["status"] == "RINGING"
        assert active_sessions[session_id]["user"]["name"] == "Alice Visitor"
        assert active_sessions[session_id]["user"]["email"] == "alice@example.com"
        assert "country" in active_sessions[session_id]

        # 4. Agent accepts visitor
        accept_resp = client.post("/api/v1/handoff/accept", json={"sessionId": session_id})
        assert accept_resp.status_code == status.HTTP_200_OK
        assert accept_resp.json()["status"] == "IN_CHAT"
        assert active_sessions[session_id]["status"] == "IN_CHAT"

        # 5. Visitor sends a message in human mode
        msg_resp = client.post("/api/v1/message", json={
            "sessionId": session_id,
            "message": "Hello Agent! Need help with order."
        })
        assert msg_resp.status_code == status.HTTP_200_OK
        assert "delivered to agent" in msg_resp.json()["reply"]

        # 6. Agent replies to visitor
        agent_reply_resp = client.post("/api/v1/handoff/message", json={
            "sessionId": session_id,
            "message": "Hi Alice! I am here to help."
        })
        assert agent_reply_resp.status_code == status.HTTP_200_OK
        assert agent_reply_resp.json()["reply"] == "Hi Alice! I am here to help."

        # 7. Visitor ends chat
        end_resp = client.post("/api/v1/handoff/end", json={"sessionId": session_id, "endedBy": "visitor"})
        assert end_resp.status_code == status.HTTP_200_OK
        assert end_resp.json()["status"] == "ENDED"
        assert end_resp.json()["endedBy"] == "visitor"

        # Verify session remains in active_sessions with ENDED status
        # (socket is still open; cleanup happens on actual disconnect)
        assert session_id in active_sessions
        assert active_sessions[session_id]["status"] == "ENDED"

        # 8. Attempting to send agent reply after chat ended must be rejected with 400 Bad Request
        rejected_reply = client.post("/api/v1/handoff/message", json={
            "sessionId": session_id,
            "message": "Attempt reply after chat ended"
        })
        assert rejected_reply.status_code == status.HTTP_400_BAD_REQUEST
        assert "ended session" in rejected_reply.json()["detail"]

def test_anonymous_active_session(client):
    domain = f"anon-{uuid.uuid4().hex[:6]}.com"
    reg_resp = client.post("/api/v1/tenant/register", json={
        "domain": domain,
        "name": "Anon Store"
    })
    site_id = reg_resp.json()["siteId"]

    headers = {"Origin": f"http://{domain}", "X-Forwarded-For": "203.0.113.195"}
    init_resp = client.post("/api/v1/session/init", json={"siteId": site_id}, headers=headers)
    session_id = init_resp.json()["sessionId"]

    with client.websocket_connect(f"/ws/session/{session_id}") as ws:
        assert session_id in active_sessions
        assert active_sessions[session_id]["user"] is None
        assert active_sessions[session_id]["ipAddress"] == "203.0.113.195"
        assert active_sessions[session_id]["status"] == "RINGING"

        # Verify GET /api/v1/admin/active-sessions returns the IP and Country
        res_admin = client.get("/api/v1/admin/active-sessions")
        assert res_admin.status_code == status.HTTP_200_OK
        matching = [s for s in res_admin.json() if s["sessionId"] == session_id]
        assert len(matching) == 1
        assert matching[0]["ipAddress"] == "203.0.113.195"
        assert "country" in matching[0]

def test_agent_ends_chat_flow(client):
    domain = f"agentend-{uuid.uuid4().hex[:6]}.com"
    reg_resp = client.post("/api/v1/tenant/register", json={
        "domain": domain,
        "name": "Agent End Test Store"
    })
    site_id = reg_resp.json()["siteId"]

    headers = {"Origin": f"http://{domain}"}
    init_resp = client.post("/api/v1/session/init", json={"siteId": site_id}, headers=headers)
    session_id = init_resp.json()["sessionId"]

    with client.websocket_connect(f"/ws/session/{session_id}") as ws:
        # Agent accepts
        accept_resp = client.post("/api/v1/handoff/accept", json={"sessionId": session_id})
        assert accept_resp.status_code == status.HTTP_200_OK
        assert active_sessions[session_id]["status"] == "IN_CHAT"

        # Receive accepted status_changed event on visitor WS
        accepted_event = ws.receive_json()
        assert accepted_event["type"] == "status_changed"
        assert accepted_event["status"] == "IN_CHAT"

        # Agent ends chat
        end_resp = client.post("/api/v1/handoff/end", json={"sessionId": session_id, "endedBy": "agent"})
        assert end_resp.status_code == status.HTTP_200_OK
        assert end_resp.json()["status"] == "ENDED"
        assert end_resp.json()["endedBy"] == "agent"
        # Session remains in active_sessions with ENDED status
        # (socket is still open; cleanup happens on actual disconnect)
        assert session_id in active_sessions
        assert active_sessions[session_id]["status"] == "ENDED"

        # Verify visitor WS received status_changed to ENDED with endedBy: agent
        ended_event = ws.receive_json()
        assert ended_event["type"] == "status_changed"
        assert ended_event["status"] == "ENDED"
        assert ended_event["endedBy"] == "agent"

        # Verify message rejection after agent ended chat
        rejected_reply = client.post("/api/v1/handoff/message", json={
            "sessionId": session_id,
            "message": "Attempt reply after chat ended"
        })
        assert rejected_reply.status_code == status.HTTP_400_BAD_REQUEST
        assert "ended session" in rejected_reply.json()["detail"]
