"""Tests for neonlink.transaction."""

import pytest

from neonlink.config import Config
from neonlink.record import Record
from neonlink.transaction import TransactionalProducer


class TestTransactionalProducerValidation:
    def test_requires_transactional_id(self):
        cfg = Config()
        assert cfg.transactional_id == ""

    def test_transactional_config_requires_id(self):
        cfg = Config()
        with pytest.raises(ValueError, match="transactional_id is required"):
            cfg.to_transactional_config()

    def test_transactional_config_forces_acks_all(self):
        cfg = Config(transactional_id="test-txn-0")
        conf = cfg.to_transactional_config()
        assert conf["acks"] == "all"
        assert conf["transactional.id"] == "test-txn-0"
        assert conf["enable.idempotence"] == "true"

    def test_transactional_config_with_tls_sasl(self):
        cfg = Config(
            transactional_id="test-txn-1",
            tls_enabled=True,
            tls_ca_file="/ca.pem",
            sasl_mechanism="SCRAM-SHA-256",
            sasl_username="user",
            sasl_password="pass",
        )
        conf = cfg.to_transactional_config()
        assert conf["security.protocol"] == "SASL_SSL"
        assert conf["transactional.id"] == "test-txn-1"
        assert conf["sasl.mechanism"] == "SCRAM-SHA-256"


class TestTransactionalIDFromLookup:
    def test_loads_from_map(self):
        from neonlink.config import new_config_from_map

        cfg = new_config_from_map({"NEONLINK_TRANSACTIONAL_ID": "findata-coordinator-0"})
        assert cfg.transactional_id == "findata-coordinator-0"

    def test_default_empty(self):
        cfg = Config()
        assert cfg.transactional_id == ""


class TestTransactionalProducerUniversalMethods:
    def test_publish_delegates_to_publish_atomic(self):
        p = object.__new__(TransactionalProducer)
        called = {}

        def _fake_publish_atomic(records, *, cancel_event=None, timeout_sec=30.0):
            called["records"] = records
            called["cancel_event"] = cancel_event
            called["timeout_sec"] = timeout_sec

        p.publish_atomic = _fake_publish_atomic

        p.publish(
            "topic-a",
            b"k",
            b"v",
            {"h": "v"},
            timeout_sec=12.0,
        )

        assert len(called["records"]) == 1
        rec = called["records"][0]
        assert rec.topic == "topic-a"
        assert rec.key == b"k"
        assert rec.value == b"v"
        assert rec.headers == {"h": "v"}
        assert called["timeout_sec"] == 12.0

    def test_publish_record_delegates_to_publish_atomic(self):
        p = object.__new__(TransactionalProducer)
        called = {}

        def _fake_publish_atomic(records, *, cancel_event=None, timeout_sec=30.0):
            called["records"] = records
            called["cancel_event"] = cancel_event
            called["timeout_sec"] = timeout_sec

        p.publish_atomic = _fake_publish_atomic

        rec = Record(topic="topic-b", key=b"k2", value=b"v2")
        p.publish_record(rec, timeout_sec=9.0)

        assert called["records"] == [rec]
        assert called["timeout_sec"] == 9.0

    def test_publish_batch_delegates_to_publish_atomic(self):
        p = object.__new__(TransactionalProducer)
        called = {}

        def _fake_publish_atomic(records, *, cancel_event=None, timeout_sec=30.0):
            called["records"] = records
            called["cancel_event"] = cancel_event
            called["timeout_sec"] = timeout_sec

        p.publish_atomic = _fake_publish_atomic

        recs = [Record(topic="topic-1"), Record(topic="topic-2")]
        p.publish_batch(recs, timeout_sec=5.0)

        assert called["records"] == recs
        assert called["timeout_sec"] == 5.0
