from datetime import datetime, timedelta, timezone
from types import SimpleNamespace
from uuid import uuid4

import pytest
from pydantic import ValidationError
from src.core.protocols import SendResult
from src.domain.admin.schemas import AdminEmailSendRequest
from src.workers import enqueue
from src.workers.tasks import admin_emails


def test_admin_email_request_rejects_duplicate_recipients():
    user_id = uuid4()

    with pytest.raises(ValidationError, match="Recipients must be unique"):
        AdminEmailSendRequest(
            user_ids=[user_id, user_id],
            from_email="team@example.com",
            subject="Welcome",
            html_body="<p>Hello</p>",
        )


@pytest.mark.asyncio
async def test_enqueue_admin_email_defers_to_scheduled_time(monkeypatch):
    scheduled_at = datetime.now(timezone.utc) + timedelta(hours=1)

    class FakeRedis:
        def __init__(self):
            self.kwargs = None

        async def enqueue_job(self, _name, **kwargs):
            self.kwargs = kwargs
            return SimpleNamespace(job_id="admin-email-job")

        async def close(self):
            pass

    redis = FakeRedis()

    async def fake_pool():
        return redis

    monkeypatch.setattr(enqueue, "_get_redis_pool", fake_pool)

    queued = await enqueue.enqueue_admin_email(
        recipient_emails=["customer@example.com"],
        from_email="team@example.com",
        subject="Welcome",
        html_body="<p>Hello</p>",
        requested_by="admin-id",
        scheduled_at=scheduled_at,
    )

    assert queued is True
    assert redis.kwargs["_defer_until"] == scheduled_at
    assert redis.kwargs["recipient_emails"] == ["customer@example.com"]


@pytest.mark.asyncio
async def test_send_admin_email_delivers_each_recipient(monkeypatch):
    sent_to = []

    class FakeProvider:
        def __init__(self, *, from_email):
            assert from_email == "team@example.com"

        async def send(self, recipient_email, subject, html_body):
            sent_to.append((recipient_email, subject, html_body))
            return SendResult(success=True, message_id=f"message-{len(sent_to)}")

    monkeypatch.setattr(admin_emails, "email_transport_configured", lambda: True)
    monkeypatch.setattr(
        admin_emails,
        "get_email_provider",
        lambda from_email=None: FakeProvider(from_email=from_email),
    )

    result = await admin_emails.send_admin_email(
        {},
        recipient_emails=["first@example.com", "second@example.com"],
        from_email="team@example.com",
        subject="Welcome",
        html_body="<p>Hello</p>",
        requested_by="admin-id",
    )

    assert result == {"sent": 2, "failed": 0, "message_ids": ["message-1", "message-2"]}
    assert [entry[0] for entry in sent_to] == ["first@example.com", "second@example.com"]
