"""Core data types for valn8n diagnostics."""

from dataclasses import dataclass, field
from enum import Enum


class Severity(Enum):
    """Diagnostic severity level."""

    HINT = "hint"
    WARNING = "warning"
    ERROR = "error"


class SuggestionLevel(Enum):
    """Controls how much suggestion detail appears in diagnostics."""

    NONE = "none"
    SHORT = "short"
    FULL = "full"


_SHORT_LIMIT = 5


def format_suggestions(valid: set[str] | list[str], level: SuggestionLevel) -> str:
    """Return '; valid values: x, y, z' suffix or '' based on level."""
    if level == SuggestionLevel.NONE:
        return ""
    items = sorted(valid) if isinstance(valid, set) else valid
    if level == SuggestionLevel.SHORT:
        shown = items[:_SHORT_LIMIT]
        suffix = f" ({len(items)} total)" if len(items) > _SHORT_LIMIT else ""
        return "; valid values: " + ", ".join(shown) + suffix
    return "; valid values: " + ", ".join(items)


class Deprecation(Enum):
    """Rule deprecation status."""

    NO = "no"
    PLANNED = "planned"
    DEPRECATED = "deprecated"


@dataclass(frozen=True)
class RuleCode:
    """A rule code like WF0001 or ND0102, with explicit severity and deprecation."""

    code: str  # e.g. "WF0001", "ND0102"
    severity: Severity
    deprecation: Deprecation = field(default=Deprecation.NO)
    description: str = ""
    strict: bool | None = None

    def __str__(self) -> str:  # noqa: D105
        return self.code


@dataclass(frozen=True)
class Location:
    """Location within a workflow node."""

    node_name: str
    field_path: str  # e.g. "parameters.conditions.0"


@dataclass(frozen=True)
class Diagnostic:
    """A single validation diagnostic."""

    file: str
    location: Location | None
    code: RuleCode
    message: str
    line: int | None = None


def parse_tolerate_node_keys(raw: str) -> frozenset[str] | None:
    """Parse a comma-separated list of node keys to tolerate in ND0201.

    Returns:
        frozenset() for empty string (tolerate nothing),
        frozenset of key names for comma-separated values,
        None for "*" (tolerate all ND0201).

    Raises:
        ValueError: if "*" is mixed with other values.

    """
    if raw == "":
        return frozenset()
    parts = [p.strip() for p in raw.split(",")]
    if "*" in parts:
        if len(parts) > 1:
            msg = "Cannot mix '*' with specific keys in --tolerate-node-keys"
            raise ValueError(msg)
        return None
    return frozenset(parts)
