from collections.abc import Mapping
from typing import (
    TypedDict,
    NotRequired,
    List,
    Any,
    Literal,
    Optional,
    TYPE_CHECKING,
    get_args,
    FrozenSet,
    cast,
)

if TYPE_CHECKING:
    import lsprotocol.types as types
else:
    import debputy.lsprotocol.types as types

# These are in order of severity (most important to least important).
#
# Special cases:
#  - "spelling" is a specialized version of "pedantic" for textual spelling mistakes
#    (LSP uses the same severity for both; only `debputy lint` shows a difference
#     between them)
#
LintSeverity = Literal["error", "warning", "informational", "pedantic", "spelling"]

LINT_SEVERITY2LSP_SEVERITY: Mapping[LintSeverity, types.DiagnosticSeverity] = {
    "error": types.DiagnosticSeverity.Error,
    "warning": types.DiagnosticSeverity.Warning,
    "informational": types.DiagnosticSeverity.Information,
    "pedantic": types.DiagnosticSeverity.Hint,
    "spelling": types.DiagnosticSeverity.Hint,
}
NATIVELY_LSP_SUPPORTED_SEVERITIES: FrozenSet[LintSeverity] = cast(
    "FrozenSet[LintSeverity]",
    frozenset(
        {
            "error",
            "warning",
            "informational",
            "pedantic",
        }
    ),
)


_delta = set(get_args(LintSeverity)).symmetric_difference(
    LINT_SEVERITY2LSP_SEVERITY.keys()
)
assert (
    not _delta
), f"LintSeverity and LINT_SEVERITY2LSP_SEVERITY are not aligned. Delta: {_delta}"
del _delta


class DiagnosticData(TypedDict):
    quickfixes: NotRequired[Optional[List[Any]]]
    lint_severity: NotRequired[Optional[LintSeverity]]
    report_for_related_file: NotRequired[str]
