from __future__ import annotations

from nats_common.settings import NatsCommonSettings


class SubjectBuilder:
    """
    A fluent builder for constructing NATS subjects.
    Existing parts are separated by dots.

    Order of parts:
    - prefix
    - device
    - version
    - service
    - event

    If using a router, don't set the parts added by the router a second time.
    Thus, using the NatsCommonSettings, the router already sets the prefix and device.

    """

    def __init__(
        self,
        prefix: str | None = None,
        device: str | None = None,
        version: str | None = None,
        service: str | None = None,
        event: str | None = None,
    ) -> None:
        self._prefix = prefix
        self._device = device
        self._version = version
        self._service = service
        self._event = event

    @staticmethod
    def from_settings(settings: NatsCommonSettings) -> SubjectBuilder:
        """Create a SubjectBuilder initialized with prefix and device from settings."""
        prefix = settings.subject_prefix
        device = settings.device
        return SubjectBuilder(prefix=prefix, device=device)

    def prefix(self, prefix: str | None) -> SubjectBuilder:
        """Set the prefix part of the subject."""
        self._prefix = prefix
        return self

    def device(self, device: str | None) -> SubjectBuilder:
        """Set the device part of the subject."""
        self._device = device
        return self

    def version(self, version: str | None) -> SubjectBuilder:
        """Set the version part of the subject."""
        self._version = version
        return self

    def service(self, service: str | None) -> SubjectBuilder:
        """Set the service part of the subject."""
        self._service = service
        return self

    def event(self, event: str | None) -> SubjectBuilder:
        """Set the event part of the subject."""
        self._event = event
        return self

    def build(self) -> str:
        """Build the subject string by joining non-None parts with dots."""
        parts = [self._prefix, self._device, self._version, self._service, self._event]
        # Filter out None values and empty strings, strip leading/trailing dots, then join with dots
        filtered_parts = [part.strip(".") for part in parts if part is not None and part.strip(".") != ""]
        return ".".join(filtered_parts)

    def __str__(self) -> str:
        return self.build()

    def __repr__(self) -> str:
        return self.build()
