"""Tests for the logging module.

These tests verify that the logging functionality works correctly
with both standard and JSON formatting, and handles various edge cases.
"""

import io
import json
import logging
import sys

from augint_library.logging import JSONFormatter, setup_logging


class TestJSONFormatter:
    """Test the JSONFormatter class."""

    def test_json_formatter_basic_message(self) -> None:
        """Test basic message formatting as JSON."""
        formatter = JSONFormatter()
        record = logging.LogRecord(
            name="test.logger",
            level=logging.INFO,
            pathname="",
            lineno=0,
            msg="Test message",
            args=(),
            exc_info=None,
        )

        result = formatter.format(record)
        parsed = json.loads(result)

        assert parsed["level"] == "INFO"
        assert parsed["logger"] == "test.logger"
        assert parsed["message"] == "Test message"
        assert "timestamp" in parsed
        assert parsed["timestamp"].endswith("+00:00")

    def test_json_formatter_with_extra_fields(self) -> None:
        """Test formatter includes extra fields from log record."""
        formatter = JSONFormatter()
        record = logging.LogRecord(
            name="test.logger",
            level=logging.ERROR,
            pathname="",
            lineno=0,
            msg="Error occurred",
            args=(),
            exc_info=None,
        )
        # Add extra fields
        record.user_id = 123
        record.request_id = "abc-123"

        result = formatter.format(record)
        parsed = json.loads(result)

        assert parsed["user_id"] == 123
        assert parsed["request_id"] == "abc-123"
        assert parsed["message"] == "Error occurred"

    def test_json_formatter_with_exception(self) -> None:
        """Test formatter handles exceptions correctly."""
        formatter = JSONFormatter()

        try:
            raise ValueError("Test exception")
        except ValueError:
            exc_info = sys.exc_info()

        record = logging.LogRecord(
            name="test.logger",
            level=logging.ERROR,
            pathname="",
            lineno=0,
            msg="Exception occurred",
            args=(),
            exc_info=exc_info,
        )

        result = formatter.format(record)
        parsed = json.loads(result)

        assert "exception" in parsed
        assert "ValueError: Test exception" in parsed["exception"]
        assert "Traceback" in parsed["exception"]

    def test_json_formatter_excludes_internal_fields(self) -> None:
        """Test formatter excludes internal logging fields."""
        formatter = JSONFormatter()
        record = logging.LogRecord(
            name="test.logger",
            level=logging.INFO,
            pathname="/path/to/file.py",
            lineno=42,
            msg="Test message",
            args=(),
            exc_info=None,
        )

        result = formatter.format(record)
        parsed = json.loads(result)

        # These internal fields should not be in JSON output
        assert "pathname" not in parsed
        assert "lineno" not in parsed
        assert "levelno" not in parsed
        assert "thread" not in parsed
        assert "process" not in parsed


class TestSetupLogging:
    """Test the setup_logging function."""

    def test_setup_logging_basic(self) -> None:
        """Test basic logger setup."""
        logger = setup_logging("test-service")

        assert logger.name == "test-service"
        assert logger.level == logging.INFO
        assert len(logger.handlers) == 1
        assert isinstance(logger.handlers[0], logging.StreamHandler)
        assert not logger.propagate

    def test_setup_logging_with_level(self) -> None:
        """Test logger setup with custom level."""
        logger = setup_logging("test-service", level="DEBUG")

        assert logger.level == logging.DEBUG

        logger = setup_logging("test-service", level="ERROR")
        assert logger.level == logging.ERROR

    def test_setup_logging_with_json_format(self) -> None:
        """Test logger setup with JSON formatting."""
        logger = setup_logging("test-service", json_format=True)

        handler = logger.handlers[0]
        assert isinstance(handler.formatter, JSONFormatter)

    def test_setup_logging_without_json_format(self) -> None:
        """Test logger setup with standard formatting."""
        logger = setup_logging("test-service", json_format=False)

        handler = logger.handlers[0]
        assert not isinstance(handler.formatter, JSONFormatter)
        assert isinstance(handler.formatter, logging.Formatter)

    def test_setup_logging_with_custom_handler(self) -> None:
        """Test logger setup with custom handler."""
        custom_handler = logging.StreamHandler()
        logger = setup_logging("test-service", handler=custom_handler)

        assert len(logger.handlers) == 1
        assert logger.handlers[0] is custom_handler

    def test_setup_logging_clears_existing_handlers(self) -> None:
        """Test that setup_logging clears existing handlers."""
        # First setup
        logger1 = setup_logging("test-service")
        assert len(logger1.handlers) == 1

        # Second setup should clear previous handlers
        logger2 = setup_logging("test-service")
        assert len(logger2.handlers) == 1
        assert logger1 is logger2  # Same logger instance

    def test_setup_logging_output_standard_format(self) -> None:
        """Test actual log output with standard formatting."""
        stream = io.StringIO()
        handler = logging.StreamHandler(stream)

        logger = setup_logging("test-service", handler=handler, json_format=False)
        logger.info("Test message")

        output = stream.getvalue()
        assert "test-service" in output
        assert "INFO" in output
        assert "Test message" in output

    def test_setup_logging_output_json_format(self) -> None:
        """Test actual log output with JSON formatting."""
        stream = io.StringIO()
        handler = logging.StreamHandler(stream)

        logger = setup_logging("test-service", handler=handler, json_format=True)
        logger.info("Test message", extra={"user_id": 123})

        output = stream.getvalue().strip()
        parsed = json.loads(output)

        assert parsed["logger"] == "test-service"
        assert parsed["level"] == "INFO"
        assert parsed["message"] == "Test message"
        assert parsed["user_id"] == 123

    def test_setup_logging_no_propagation(self) -> None:
        """Test that logger doesn't propagate to root logger."""
        logger = setup_logging("test-service")
        assert logger.propagate is False

    def test_setup_logging_uses_stdout_by_default(self) -> None:
        """Test that default handler uses stdout."""
        logger = setup_logging("test-service")
        handler = logger.handlers[0]

        assert isinstance(handler, logging.StreamHandler)
        assert handler.stream is sys.stdout


class TestLoggingIntegration:
    """Integration tests for logging functionality."""

    def test_logger_works_with_different_levels(self) -> None:
        """Test logger works correctly with different log levels."""
        stream = io.StringIO()
        handler = logging.StreamHandler(stream)

        logger = setup_logging("test-service", level="WARNING", handler=handler, json_format=True)

        logger.debug("Debug message")  # Should not appear
        logger.info("Info message")  # Should not appear
        logger.warning("Warning message")  # Should appear
        logger.error("Error message")  # Should appear

        output = stream.getvalue()
        lines = [line for line in output.strip().split("\n") if line]

        assert len(lines) == 2  # Only warning and error

        warning_log = json.loads(lines[0])
        error_log = json.loads(lines[1])

        assert warning_log["level"] == "WARNING"
        assert warning_log["message"] == "Warning message"
        assert error_log["level"] == "ERROR"
        assert error_log["message"] == "Error message"

    def test_multiple_loggers_independent(self) -> None:
        """Test that multiple loggers work independently."""
        stream1 = io.StringIO()
        stream2 = io.StringIO()

        logger1 = setup_logging("service1", handler=logging.StreamHandler(stream1))
        logger2 = setup_logging("service2", handler=logging.StreamHandler(stream2))

        logger1.info("Message from service1")
        logger2.info("Message from service2")

        output1 = stream1.getvalue()
        output2 = stream2.getvalue()

        assert "service1" in output1
        assert "Message from service1" in output1
        assert "service1" not in output2

        assert "service2" in output2
        assert "Message from service2" in output2
        assert "service2" not in output1
