import dataclasses
from typing import List, Optional, FrozenSet, TYPE_CHECKING

from debputy.lsp.lsp_features import SEMANTIC_TOKENS_LEGEND
from debputy.util import grouper

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


@dataclasses.dataclass(slots=True, frozen=True)
class ResolvedSemanticToken:
    range: types.Range
    value: str
    token_name: str
    modifiers: frozenset[str] = frozenset()


def resolved_semantic_token(
    line_no: int,
    col_start: int,
    value: str,
    token_type: str,
    *,
    token_modifiers: frozenset[str] = frozenset(),
) -> ResolvedSemanticToken:
    return ResolvedSemanticToken(
        types.Range(
            types.Position(
                line_no,
                col_start,
            ),
            types.Position(
                line_no,
                col_start + len(value),
            ),
        ),
        value,
        token_type,
        token_modifiers,
    )


def resolve_semantic_tokens(
    lines: list[str],
    token_result: types.SemanticTokens,
) -> list[ResolvedSemanticToken]:
    assert (len(token_result.data) % 5) == 0
    current_line = 0
    current_col = 0
    resolved_tokens = []
    token_types = SEMANTIC_TOKENS_LEGEND.token_types
    for token_data in grouper(token_result.data, 5, incomplete="strict"):
        line_delta, col_start_delta, token_len, token_code, modifier_codes = token_data
        if line_delta:
            current_col = 0
        current_line += line_delta
        current_col += col_start_delta
        assert (
            not modifier_codes
        ), "TODO: Modifiers not supported (no modifiers defined)"

        value = lines[current_line][current_col : current_col + token_len]

        resolved_tokens.append(
            resolved_semantic_token(
                current_line,
                current_col,
                value,
                token_types[token_code],
            ),
        )

    return resolved_tokens
