# Copyright 2026, Jiri Eischmann <jiri@eischmann.cz> and the meshy contributors
# SPDX-License-Identifier: GPL-3.0-or-later

"""SMAZ decompression for interoperability with meshcore-open clients.

Meshcore-open can compress short text messages using the SMAZ algorithm
(dictionary-based compression for short ASCII strings). Compressed messages
are sent with an 's:' prefix followed by base64-encoded SMAZ data.
"""

import base64

_VERBATIM_SINGLE = 254
_VERBATIM_RUN = 255

_CODEBOOK = [
    " ", "the", "e", "t", "a", "of", "o", "and", "i", "n",
    "s", "e ", "r", " th", " t", "in", "he", "th", "h", "he ",
    "to", "\r\n", "l", "s ", "d", " a", "an", "er", "c", " o",
    "d ", "on", " of", "re", "of ", "t ", ", ", "is", "u", "at",
    "   ", "n ", "or", "which", "f", "m", "as", "it", "that", "\n",
    "was", "en", "  ", " w", "es", " an", " i", "\r", "f ", "g",
    "p", "nd", " s", "nd ", "ed ", "w", "ed", "http://", "for", "te",
    "ing", "y ", "The", " c", "ti", "r ", "his", "st", " in", "ar",
    "nt", ",", " to", "y", "ng", " h", "with", "le", "al", "to ",
    "b", "ou", "be", "were", " b", "se", "o ", "ent", "ha", "ng ",
    "their", "\"", "hi", "from", " f", "in ", "de", "ion", "me", "v",
    ".", "ve", "all", "re ", "ri", "ro", "is ", "co", "f t", "are",
    "ea", ". ", "her", " m", "er ", " p", "es ", "by", "they", "di",
    "ra", "ic", "not", "s, ", "d t", "at ", "ce", "la", "h ", "ne",
    "as ", "tio", "on ", "n t", "io", "we", " a ", "om", ", a", "s o",
    "ur", "li", "ll", "ch", "had", "this", "e t", "g ", "e\r\n", " wh",
    "ere", " co", "e o", "a ", "us", " d", "ss", "\n\r\n", "\r\n\r", "=\"",
    " be", " e", "s a", "ma", "one", "t t", "or ", "but", "el", "so",
    "l ", "e s", "s,", "no", "ter", " wa", "iv", "ho", "e a", " r",
    "hat", "s t", "ns", "ch ", "wh", "tr", "ut", "/", "have", "ly ",
    "ta", " ha", " on", "tha", "-", " l", "ati", "en ", "pe", " re",
    "there", "ass", "si", " fo", "wa", "ec", "our", "who", "its", "z",
    "fo", "rs", ">", "ot", "un", "<", "im", "th ", "nc", "ate",
    "><", "ver", "ad", " we", "ly", "ee", " n", "id", " cl", "ac",
    "il", "</", "rt", " wi", "div", "e, ", " it", "whi", " ma", "ge",
    "x", "e c", "men", ".com",
]

_CODEBOOK_BYTES = [entry.encode('ascii') for entry in _CODEBOOK]


def _decompress(data: bytes) -> bytes:
    out = bytearray()
    i = 0
    while i < len(data):
        code = data[i]
        if code == _VERBATIM_SINGLE:
            if i + 1 >= len(data):
                break
            out.append(data[i + 1])
            i += 2
        elif code == _VERBATIM_RUN:
            if i + 1 >= len(data):
                break
            length = data[i + 1] + 1
            end = i + 2 + length
            if end > len(data):
                break
            out.extend(data[i + 2:end])
            i = end
        elif code < len(_CODEBOOK_BYTES):
            out.extend(_CODEBOOK_BYTES[code])
            i += 1
        else:
            break
    return bytes(out)


def try_decode_prefixed(text: str) -> str:
    """If text starts with 's:', decode base64 + SMAZ. Otherwise return as-is."""
    stripped = text.lstrip()
    if not stripped.startswith('s:') or len(stripped) <= 2:
        return text
    encoded = stripped[2:]
    try:
        compressed = base64.b64decode(encoded, validate=True)
    except Exception:
        try:
            normalized = encoded.replace('-', '+').replace('_', '/')
            pad = len(normalized) % 4
            if pad:
                normalized += '=' * (4 - pad)
            compressed = base64.b64decode(normalized)
        except Exception:
            return text
    try:
        return _decompress(compressed).decode('utf-8', errors='replace')
    except Exception:
        return text
