from dataclasses import dataclass, field, fields
from typing import Dict


@dataclass
class BasePVInterface:
    """
    A base configuration class for EPICS PV interfaces.

    This class handles the dynamic construction of PV names based on provided
    prefixes. It supports inheritance, allowing users to define sets of PVs
    (templates) and instantiate them with specific device prefixes.

    Attributes:
        prefixes (Dict[str, str]):
        A dictionary of prefixes used to format the PV templates.
        Example: {'sys': 'VAC:01:', 'main': 'PUMP:A:'}
    """

    # 1. Configuration: Holds the prefixes used for formatting
    prefixes: Dict[str, str] = field(default_factory=dict)

    # 2. Default PV Templates (Note: These use the '{main}' key)
    trigger: str = "{main}Trigger"
    heartbeat: str = "{main}Heartbeat"
    busy: str = "{main}Busy"
    task_status: str = "{main}TaskStatus"
    task_duration: str = "{main}TaskDuration"

    def __post_init__(self):
        """
        Post-initialization hook.
        Iterates through all string fields in the instance. If a field contains
        Python format placeholders (e.g., "{sys}Name"), it formats the string
        using the provided `prefixes` dictionary.
        """
        missing_keys = []

        for f in fields(self):
            # Skip internal configuration fields
            if f.name == "prefixes":
                continue

            # Get the raw value (the template, e.g., "{sys}Trigger")
            raw_template = getattr(self, f.name)

            # Only process strings that look like templates
            if isinstance(raw_template, str) and "{" in raw_template:
                try:
                    # FIX: Changed 'self.context' to 'self.prefixes'
                    formatted_pv = raw_template.format(**self.prefixes)
                    setattr(self, f.name, formatted_pv)
                except KeyError as e:
                    # Collect errors to show them all at once
                    missing_keys.append(f"Field '{f.name}' requires prefix key {e}")

        if missing_keys:
            raise ValueError(
                "Configuration Error: Missing prefixes for PV templates.\n"
                + "\n".join(missing_keys)
            )

    @property
    def as_dict(self) -> Dict[str, str]:
        """Returns a dictionary of PVs, excluding the internal 'prefixes'."""
        # vars(self) is faster than asdict(self)
        # We use .copy() to ensure we don't modify the actual object
        data = vars(self).copy()

        # Remove the configuration field so you only get PVs
        if "prefixes" in data:
            del data["prefixes"]

        return data

    @property
    def pv_to_attr(self) -> Dict[str, str]:
        """
        Returns a reverse mapping: {Formatted_PV_Name: Attribute_Name}.
        Example: {'VAC:01:Trigger': 'trigger'}
        """
        # Invert the dictionary: value becomes key, key becomes value
        return {v: k for k, v in self.as_dict.items()}
