"""Compile .po files to .mo files without requiring msgfmt."""
import struct
import os


def _unescape(s: str) -> str:
    """Unescape PO string escape sequences."""
    return s.replace("\\n", "\n").replace("\\t", "\t").replace("\\r", "\r").replace('\\"', '"').replace("\\\\", "\\")


def _extract_quoted(line: str) -> str:
    """Extract content from a quoted PO string line, unescape it."""
    if line.startswith('"') and line.endswith('"'):
        return _unescape(line[1:-1])
    return line


def make_mo(po_path, mo_path):
    """Minimal .po → .mo compiler."""
    entries = []
    msgid = None
    msgstr = None
    in_msgid = False
    in_msgstr = False

    with open(po_path, encoding="utf-8") as f:
        for line in f:
            line = line.strip()
            if line.startswith("msgid "):
                if msgid is not None and msgstr is not None:
                    entries.append((msgid, msgstr))
                msgid = _extract_quoted(line[6:].strip())
                msgstr = ""
                in_msgid = True
                in_msgstr = False
            elif line.startswith("msgstr "):
                msgstr = _extract_quoted(line[7:].strip())
                in_msgid = False
                in_msgstr = True
            elif line.startswith('"') and line.endswith('"'):
                content = _unescape(line[1:-1])
                if in_msgid and msgid is not None:
                    msgid += content
                elif in_msgstr and msgstr is not None:
                    msgstr += content
            else:
                in_msgid = False
                in_msgstr = False

    if msgid is not None and msgstr is not None:
        entries.append((msgid, msgstr))

    # Filter: keep entries with non-empty msgstr (including header with empty msgid)
    entries = [(k, v) for k, v in entries if v]
    entries.sort(key=lambda x: x[0])

    keys = [k.encode("utf-8") for k, v in entries]
    vals = [v.encode("utf-8") for k, v in entries]
    n = len(keys)

    header_size = 7 * 4
    key_off_start = header_size
    val_off_start = key_off_start + n * 8
    key_data_start = val_off_start + n * 8
    val_data_start = key_data_start + sum(len(k) + 1 for k in keys)

    key_offsets = []
    off = key_data_start
    for k in keys:
        key_offsets.append((len(k), off))
        off += len(k) + 1

    val_offsets = []
    off = val_data_start
    for v in vals:
        val_offsets.append((len(v), off))
        off += len(v) + 1

    buf = bytearray()
    buf += struct.pack("<I", 0x950412DE)  # magic
    buf += struct.pack("<I", 0)           # revision
    buf += struct.pack("<I", n)           # count
    buf += struct.pack("<I", key_off_start)
    buf += struct.pack("<I", val_off_start)
    buf += struct.pack("<I", 0)           # hash size
    buf += struct.pack("<I", 0)           # hash offset

    for length, offset in key_offsets:
        buf += struct.pack("<II", length, offset)
    for length, offset in val_offsets:
        buf += struct.pack("<II", length, offset)

    for k in keys:
        buf += k + b"\x00"
    for v in vals:
        buf += v + b"\x00"

    os.makedirs(os.path.dirname(mo_path), exist_ok=True)
    with open(mo_path, "wb") as f:
        f.write(buf)
    print(f"Written {mo_path} ({n} entries)")


if __name__ == "__main__":
    base = os.path.dirname(__file__)
    locale_dir = os.path.join(base, "locale")
    for lang in ("fa", "ar"):
        po = os.path.join(locale_dir, lang, "LC_MESSAGES", "django.po")
        mo = os.path.join(locale_dir, lang, "LC_MESSAGES", "django.mo")
        if os.path.exists(po):
            make_mo(po, mo)
        else:
            print(f"Skipping {lang}: {po} not found")
