"""Tests for Phase 2 logger core (no transports)."""

from __future__ import annotations

import pathlib
import sys
import unittest


ROOT = pathlib.Path(__file__).resolve().parents[1]
SRC = ROOT / "src"
if str(SRC) not in sys.path:
    sys.path.insert(0, str(SRC))

from vedatrace import VedaTrace
from vedatrace._engine import Engine
from vedatrace.config import VedaTraceConfig
from vedatrace.logger import Logger
from vedatrace.models import LogLevel


class TestLoggerCore(unittest.TestCase):
    def setUp(self) -> None:
        self.config = VedaTraceConfig(api_key="test-key", service="orders")
        self.engine = Engine(self.config)
        self.logger = Logger(self.config, self.engine)

    def test_public_methods_can_be_called_without_raising(self) -> None:
        self.logger.debug("d")
        self.logger.info("i")
        self.logger.warning("w")
        self.logger.error("e")
        self.logger.fatal("f")
        self.logger.flush()
        self.logger.close()

    def test_log_call_creates_record_and_engine_stores_it(self) -> None:
        self.logger.info("hello world", metadata={"request_id": "abc-123"})
        records = self.engine._test_records
        self.assertEqual(len(records), 1)
        record = records[0]
        self.assertEqual(record.level, LogLevel.INFO)
        self.assertEqual(record.message, "hello world")
        self.assertEqual(record.service, "orders")
        self.assertEqual(record.metadata, {"request_id": "abc-123"})

    def test_metadata_none_defaults_to_empty_dict(self) -> None:
        self.logger.debug("no metadata")
        record = self.engine._test_records[0]
        self.assertEqual(record.metadata, {})

    def test_metadata_provided_is_stored_on_record(self) -> None:
        self.logger.info("with metadata", metadata={"request_id": "abc-123"})
        record = self.engine._test_records[0]
        self.assertEqual(record.metadata, {"request_id": "abc-123"})

    def test_default_metadata_is_merged_and_call_overrides(self) -> None:
        logger = Logger(
            self.config,
            self.engine,
            default_metadata={"env": "prod", "request_id": "from-default"},
        )

        logger.info("with defaults", metadata={"request_id": "from-call"})

        record = self.engine._test_records[0]
        self.assertEqual(
            record.metadata,
            {"env": "prod", "request_id": "from-call"},
        )

    def test_caller_metadata_dict_is_not_mutated(self) -> None:
        caller_metadata = {"request_id": "abc-123"}
        self.logger.info("copy metadata", metadata=caller_metadata)
        self.assertEqual(caller_metadata, {"request_id": "abc-123"})

        caller_metadata["request_id"] = "changed"
        record = self.engine._test_records[0]
        self.assertEqual(record.metadata["request_id"], "abc-123")

    def test_service_override_is_used_for_record(self) -> None:
        logger = Logger(
            self.config,
            self.engine,
            service="payments",
        )

        logger.info("uses service override")

        record = self.engine._test_records[0]
        self.assertEqual(record.service, "payments")

    def test_factory_returns_logger_and_logs(self) -> None:
        logger = VedaTrace(api_key="factory-key", service="billing")
        self.assertIsInstance(logger, Logger)
        logger.info("from-factory")
        self.assertEqual(len(logger._engine._test_records), 1)

    def test_factory_uses_provided_config_as_is(self) -> None:
        provided = VedaTraceConfig(api_key="provided-key", service="provided-service")
        logger = VedaTrace(
            api_key="ignored-key",
            service="ignored-service",
            config=provided,
        )
        self.assertIs(logger._config, provided)
        logger.info("uses-provided")
        record = logger._engine._test_records[0]
        self.assertEqual(record.service, "provided-service")

    def test_emit_failure_is_swallowed(self) -> None:
        self.engine._set_fail_emit_for_tests(True)
        self.logger.debug("should not raise")
        self.assertEqual(len(self.engine._test_records), 0)

    def test_emit_failure_calls_on_error_once(self) -> None:
        seen: list[Exception] = []

        def on_error(exc: Exception) -> None:
            seen.append(exc)

        config = VedaTraceConfig(
            api_key="test-key",
            service="orders",
            on_error=on_error,
        )
        engine = Engine(config)
        engine._set_fail_emit_for_tests(True)
        logger = Logger(config, engine)

        logger.debug("should call on_error")

        self.assertEqual(len(seen), 1)
        self.assertIsInstance(seen[0], RuntimeError)

    def test_emit_failure_and_on_error_failure_is_swallowed(self) -> None:
        def on_error(_: Exception) -> None:
            raise RuntimeError("on_error failed")

        config = VedaTraceConfig(
            api_key="test-key",
            service="orders",
            on_error=on_error,
        )
        engine = Engine(config)
        engine._set_fail_emit_for_tests(True)
        logger = Logger(config, engine)

        logger.debug("still should not raise")
        self.assertEqual(len(engine._test_records), 0)
