# (c) Copyright IBM Corp. 2021
# (c) Copyright Instana Inc. 2020


from typing import Optional

from opentelemetry.trace.span import format_span_id

from instana.log import logger
from instana.propagators.base_propagator import BasePropagator, CarrierT
from instana.span_context import SpanContext
from instana.util.ids import define_server_timing


class TextPropagator(BasePropagator):
    """
    Instana context propagator for TEXT_MAP.

    The TEXT_MAP deals with key-values with string to string mapping.
    The character set is unrestricted.
    """

    def inject(
        self,
        span_context: SpanContext,
        carrier: CarrierT,
        disable_w3c_trace_context: bool = True,
    ) -> Optional[CarrierT]:
        try:
            trace_id = format_span_id(span_context.trace_id)
            span_id = format_span_id(span_context.span_id)
            server_timing = define_server_timing(span_context.trace_id).encode()

            if isinstance(carrier, dict) or hasattr(carrier, "__dict__"):
                carrier[self.LC_HEADER_KEY_T] = trace_id  # type: ignore[index]
                carrier[self.LC_HEADER_KEY_S] = span_id  # type: ignore[index]
                carrier[self.LC_HEADER_KEY_L] = "1"  # type: ignore[index]
                carrier[self.LC_HEADER_KEY_SERVER_TIMING] = server_timing  # type: ignore[index]
            elif isinstance(carrier, list):
                carrier.append((self.LC_HEADER_KEY_T, trace_id))
                carrier.append((self.LC_HEADER_KEY_S, span_id))
                carrier.append((self.LC_HEADER_KEY_L, "1"))
                carrier.append((self.LC_HEADER_KEY_SERVER_TIMING, server_timing))
            elif isinstance(carrier, tuple):
                carrier = carrier.__add__(((self.LC_HEADER_KEY_T, trace_id),))
                carrier = carrier.__add__(((self.LC_HEADER_KEY_S, span_id),))
                carrier = carrier.__add__(((self.LC_HEADER_KEY_L, "1"),))
                carrier = carrier.__add__(
                    ((self.LC_HEADER_KEY_SERVER_TIMING, server_timing),)
                )
            elif hasattr(carrier, "__setitem__"):
                carrier.__setitem__(self.LC_HEADER_KEY_T, trace_id)
                carrier.__setitem__(self.LC_HEADER_KEY_S, span_id)
                carrier.__setitem__(self.LC_HEADER_KEY_L, "1")
                carrier.__setitem__(self.LC_HEADER_KEY_SERVER_TIMING, server_timing)
            else:
                raise Exception("Unsupported carrier type", type(carrier))

            return carrier
        except Exception:
            logger.debug("inject error:", exc_info=True)
