from __future__ import annotations

from dataclasses import dataclass
from typing import Dict, List, Tuple


SEMANTIC_CLASSES = ["entity", "action", "quality", "relation", "abstract"]
ONSETS = ["p", "t", "k", "m", "n", "s", "l", "r", "h", "w", "y"]
VOWELS = ["a", "e", "i", "o", "u"]
CODAS = ["", "n", "k", "s", "m", "l", "r"]

PUA_START = 0xE100
CLASS_TAG = {
    "entity": "e",
    "action": "a",
    "quality": "q",
    "relation": "r",
    "abstract": "x",
}


@dataclass(frozen=True)
class RootSpec:
    root: str
    gloss: str
    semantic_class: str
    onset: str
    vowel: str
    coda: str
    symbol_id: str
    codepoint: int

    @property
    def char(self) -> str:
        return chr(self.codepoint)

    @property
    def symbol(self) -> str:
        return ascii_symbol(self.semantic_class, self.onset, self.vowel, self.coda)


def compose_root(onset: str, vowel: str, coda: str) -> str:
    return f"{onset}{vowel}{coda}"


def symbol_id(semantic_class: str, onset: str, vowel: str, coda: str) -> str:
    return f"{semantic_class}:{onset}:{vowel}:{coda or '_'}"


def ascii_symbol(semantic_class: str, onset: str, vowel: str, coda: str) -> str:
    tag = CLASS_TAG.get(semantic_class, "e")
    return f"lg_{tag}_{onset}{vowel}{coda or '_'}"


def enumerate_symbol_space(limit: int) -> List[Tuple[str, str, str, str]]:
    out: List[Tuple[str, str, str, str]] = []
    for sc in SEMANTIC_CLASSES:
        for o in ONSETS:
            for v in VOWELS:
                for c in CODAS:
                    out.append((sc, o, v, c))
                    if len(out) >= limit:
                        return out
    return out


def vowel_anchor(vowel: str) -> Tuple[int, int]:
    anchors: Dict[str, Tuple[int, int]] = {
        "a": (500, 760),
        "e": (780, 500),
        "i": (500, 240),
        "o": (220, 500),
        "u": (500, 500),
    }
    return anchors[vowel]


def onset_vector(onset: str) -> Tuple[int, int]:
    vecs: Dict[str, Tuple[int, int]] = {
        "p": (0, 260),
        "t": (260, 0),
        "k": (0, -260),
        "m": (-260, 0),
        "n": (180, 180),
        "s": (180, -180),
        "l": (-180, -180),
        "r": (-180, 180),
        "h": (0, 320),
        "w": (320, 0),
        "y": (-320, 0),
    }
    return vecs[onset]


def coda_style(coda: str) -> str:
    styles = {
        "": "none",
        "n": "short_tick",
        "k": "angle_tick",
        "s": "double_tick",
        "m": "bar",
        "l": "hook",
        "r": "cross_tick",
    }
    return styles[coda]
