"""Default designator type names (singular/plural) by letter prefix."""

from __future__ import annotations

import re

# Minimal useful defaults; projects can override via DB
DEFAULT_MAPPINGS: dict[str, tuple[str, str]] = {
    "C": ("Конденсатор", "Конденсаторы"),
    "R": ("Резистор", "Резисторы"),
    "L": ("Катушка индуктивности", "Катушки индуктивности"),
    "D": ("Диод", "Диоды"),
    "VD": ("Диод", "Диоды"),
    "VT": ("Транзистор", "Транзисторы"),
    "Q": ("Транзистор", "Транзисторы"),
    "DA": ("Микросхема", "Микросхемы"),
    "DD": ("Микросхема", "Микросхемы"),
    "U": ("Микросхема", "Микросхемы"),
    "X": ("Соединитель", "Соединители"),
    "XP": ("Соединитель", "Соединители"),
    "XS": ("Соединитель", "Соединители"),
    "FU": ("Предохранитель", "Предохранители"),
    "F": ("Предохранитель", "Предохранители"),
    "SA": ("Переключатель", "Переключатели"),
    "SB": ("Кнопка", "Кнопки"),
    "HL": ("Индикатор", "Индикаторы"),
    "HG": ("Индикатор", "Индикаторы"),
    "G": ("Генератор", "Генераторы"),
    "T": ("Трансформатор", "Трансформаторы"),
    "TV": ("Трансформатор", "Трансформаторы"),
    "K": ("Реле", "Реле"),
    "B": ("Пьезоэлемент", "Пьезоэлементы"),
    "Z": ("Фильтр", "Фильтры"),
}


def split_designator(designator: str) -> tuple[str, str]:
    m = re.match(r"^([A-Za-z]+)(\d*)$", designator.strip())
    if m:
        return m.group(1), m.group(2)
    for i, ch in enumerate(designator):
        if ch.isdigit():
            return designator[:i], designator[i:]
    return designator, ""


def designator_sort_key(designator: str) -> tuple[str, int, str]:
    letter, num = split_designator(designator)
    try:
        n = int(num) if num else 0
    except ValueError:
        n = 0
        return letter, n, num
    return letter.upper(), n, num


def prefix_from_designator(designator: str) -> str:
    letter, _ = split_designator(designator)
    return letter.upper()


def get_type_names(
    designator: str, mappings: dict[str, tuple[str, str]] | None = None
) -> tuple[str, str]:
    maps = {**DEFAULT_MAPPINGS, **(mappings or {})}
    prefix = prefix_from_designator(designator)
    if prefix in maps:
        return maps[prefix]
    # try 2-letter then 1-letter
    if len(prefix) >= 2 and prefix[:2] in maps:
        return maps[prefix[:2]]
    if prefix[:1] in maps:
        return maps[prefix[:1]]
    return (prefix, prefix)


def format_designator_range(designators: list[str]) -> str:
    if not designators:
        return ""
    if len(designators) == 1:
        return designators[0]
    if len(designators) == 2:
        return f"{designators[0]}, {designators[1]}"
    return f"{designators[0]}-{designators[-1]}"


def format_consecutive_ranges(designators: list[str]) -> str:
    """Group consecutive numbered designators into ranges."""
    if not designators:
        return ""
    parsed = []
    for d in designators:
        letter, num = split_designator(d)
        try:
            n = int(num) if num else None
        except ValueError:
            n = None
        parsed.append((d, letter, n))

    segments: list[list[str]] = []
    current: list[str] = []
    last_letter = None
    last_num = None
    for d, letter, n in parsed:
        if not current:
            current = [d]
            last_letter, last_num = letter, n
            continue
        if letter == last_letter and n is not None and last_num is not None and n == last_num + 1:
            current.append(d)
            last_num = n
        else:
            segments.append(current)
            current = [d]
            last_letter, last_num = letter, n
    if current:
        segments.append(current)

    parts = []
    for seg in segments:
        if len(seg) == 1:
            parts.append(seg[0])
        elif len(seg) == 2:
            parts.append(f"{seg[0]}, {seg[1]}")
        else:
            parts.append(f"{seg[0]}-{seg[-1]}")
    return ", ".join(parts)


def split_long_text(text: str, max_length: int) -> list[str]:
    if not text or len(text) <= max_length:
        return [text] if text is not None else [""]
    parts: list[str] = []
    remaining = text
    while len(remaining) > max_length:
        chunk = remaining[:max_length]
        split_at = chunk.rfind(",")
        if split_at < max_length // 3:
            split_at = chunk.rfind(" ")
        if split_at < max_length // 3:
            split_at = max_length
        parts.append(remaining[:split_at].rstrip(", ").strip())
        remaining = remaining[split_at:].lstrip(", ").strip()
    if remaining:
        parts.append(remaining)
    return parts or [""]


def resolve_expression(value: str, props: dict[str, str]) -> str:
    if not value.startswith("="):
        return value
    expr = value[1:]
    result = []
    i = 0
    while i < len(expr):
        ch = expr[i]
        if ch in "'\"":
            quote = ch
            i += 1
            start = i
            while i < len(expr) and expr[i] != quote:
                i += 1
            result.append(expr[start:i])
            i += 1
        elif ch == "+":
            i += 1
        elif ch.isspace():
            i += 1
        else:
            start = i
            while i < len(expr) and expr[i] not in "+'\"":
                i += 1
            key = expr[start:i].strip()
            val = props.get(key, "")
            if val.startswith("="):
                val = resolve_expression(val, props)
            result.append(val)
    return "".join(result)
