"""Loads and resolves robot error codes from a 3-column semicolon file.

The file maps an upstream error code (the string emitted in
RobotState.hardware_state_string) to a short readable title and a longer
description that the OperatorHMI shows in the error banner and detail dialog.
Users supply their own codes by editing the file or pointing the
`errorCodesFile` config entry at a custom path.
"""
import os


NO_ERROR_CODES = {"", "NoError"}


def load_error_codes(path):
    """Parse the lookup file into ``{code: {"title": str, "description": str}}``.

    Missing files and malformed lines are tolerated silently — callers get
    whatever rows parsed cleanly. An empty dict means "no lookups available";
    every code will fall through to its raw form.
    """
    table = {}
    if not path or not os.path.isfile(path):
        return table
    with open(path, "r", encoding="utf-8") as f:
        for raw in f:
            line = raw.strip()
            if not line:
                continue
            cells = [c.strip() for c in line.split(";")]
            if len(cells) < 3:
                continue
            code, title, desc = cells[0], cells[1], cells[2]
            if not code or code.startswith("-") or code.lower() == "code":
                continue
            table[code] = {"title": title, "description": desc}
    return table


def resolve(table, code):
    """Look up a code; return display title + description.

    - Empty / "NoError" → both empty (banner stays hidden).
    - Known code → mapped title and description.
    - Unknown code → title falls back to the raw code, description is empty.
    """
    if code in NO_ERROR_CODES:
        return {"title": "", "description": ""}
    entry = table.get(code)
    if entry is None:
        return {"title": code, "description": ""}
    return entry
