from io import StringIO
from unittest.mock import patch

from django.core.management import call_command
from django.core.management.base import CommandError
from django.test import TestCase, override_settings

from core.events.ledger import append_event_sync
from core.models import ChatSession, Person, PersonIdentifier, User


@override_settings(EVENT_LEDGER_DUAL_WRITE=True)
class EventLedgerSmokeCommandTests(TestCase):
    def setUp(self):
        self.user = User.objects.create_user(
            username="ledger-smoke-user",
            email="ledger-smoke@example.com",
            password="pw",
        )
        person = Person.objects.create(user=self.user, name="Smoke Person")
        identifier = PersonIdentifier.objects.create(
            user=self.user,
            person=person,
            service="signal",
            identifier="+15550001111",
        )
        self.session = ChatSession.objects.create(user=self.user, identifier=identifier)

    def test_smoke_command_reports_recent_rows(self):
        append_event_sync(
            user=self.user,
            session=self.session,
            ts=1770000000000,
            event_type="message_created",
            direction="in",
            origin_transport="signal",
            origin_message_id="abc",
            payload={"message_id": "m1"},
        )
        out = StringIO()
        call_command(
            "event_ledger_smoke",
            user_id=str(self.user.id),
            minutes=999999,
            stdout=out,
        )
        rendered = out.getvalue()
        self.assertIn("event-ledger-smoke", rendered)
        self.assertIn("event_type_counts=", rendered)

    def test_smoke_command_validates_required_types(self):
        append_event_sync(
            user=self.user,
            session=self.session,
            ts=1770000000001,
            event_type="message_created",
            direction="in",
            origin_transport="signal",
            origin_message_id="m-required",
            payload={"message_id": "m-required"},
        )
        out = StringIO()
        call_command(
            "event_ledger_smoke",
            user_id=str(self.user.id),
            minutes=999999,
            require_types="message_created",
            stdout=out,
        )
        rendered = out.getvalue()
        self.assertIn("required_types=", rendered)
        self.assertIn("missing_required_types=[]", rendered)

    def test_smoke_command_errors_when_required_type_missing(self):
        with self.assertRaises(CommandError):
            call_command(
                "event_ledger_smoke",
                user_id=str(self.user.id),
                minutes=999999,
                require_types="reaction_added",
                stdout=StringIO(),
            )

    def test_smoke_command_errors_when_empty_and_fail_if_empty(self):
        with self.assertRaises(CommandError):
            call_command(
                "event_ledger_smoke",
                user_id=str(self.user.id),
                minutes=1,
                fail_if_empty=True,
                stdout=StringIO(),
            )

    @patch("core.management.commands.event_ledger_smoke.get_recent_event_rows")
    def test_smoke_command_falls_back_to_manticore_rows(self, mocked_rows):
        mocked_rows.return_value = [
            {
                "id": "",
                "user_id": int(self.user.id),
                "session_id": str(self.session.id),
                "ts": 1770000000002,
                "event_type": "message_created",
                "kind": "message_sent",
                "direction": "in",
                "origin_transport": "signal",
                "trace_id": "",
            }
        ]
        out = StringIO()
        call_command(
            "event_ledger_smoke",
            user_id=str(self.user.id),
            minutes=999999,
            stdout=out,
        )
        rendered = out.getvalue()
        self.assertIn("source=manticore", rendered)
        self.assertIn("event_type_counts=", rendered)
