#!/usr/bin/env python3
"""
Parser for himalaya v2.0.0 `envelope list` table output.

Why this exists
---------------
v2.0.0 removed `--output json` from `envelope list`. The only output is a
fixed-width table using `┆` (U+2506) as a column separator, capped at ~177
chars total width. Long subjects get truncated mid-word and the columns after
them shift left, so naive `split("│")` gives wrong results.

This script:
  1. Parses the table with fixed-width column slicing (NOT splits).
  2. Detects truncated subjects (≥ 85 chars in the SUBJECT field).
  3. For truncated rows, fetches the full subject via `himalaya message read`.

Usage
-----
  # Print envelopes as JSON (one per line, no truncation):
  python parse-himalaya-envelope.py

  # As a library:
  from parse_himalaya_envelope import parse_envelope_table, fetch_envelopes
  envelopes = fetch_envelopes(page=1, page_size=50)
"""

from __future__ import annotations

import json
import re
import subprocess
import sys
from pathlib import Path

HIMALAYA = Path.home() / ".local" / "bin" / "himalaya.exe"

# Column boundaries in the v2 table output (verified empirically, do not change):
COL_ID      = (0,   7)    # ID
COL_FLAGS   = (7,   15)   # FLAGS
COL_SUBJECT = (15,  105)  # SUBJECT  (~90 chars)
COL_FROM    = (105, 138)  # FROM
COL_DATE    = (138, 163)  # DATE
COL_SIZE    = (163, 177)  # SIZE


def parse_envelope_table(text: str) -> list[dict]:
    """Parse the v2 fixed-width envelope table into a list of dicts."""
    envelopes: list[dict] = []
    data_lines = []
    for line in text.splitlines():
        if line.startswith("│") and not line.startswith("╞") and not line.startswith("└") \
                and "ID" not in line and "SUBJECT" not in line:
            data_lines.append(line)
    for line in data_lines:
        if len(line) < 177:
            continue
        id_ = line[COL_ID[0]:COL_ID[1]].replace("│", "").replace("┆", "").strip()
        if not id_.isdigit():
            continue
        subject = line[COL_SUBJECT[0]:COL_SUBJECT[1]].strip()
        sender  = line[COL_FROM[0]:COL_FROM[1]].strip()
        date    = line[COL_DATE[0]:COL_DATE[1]].strip()
        size    = line[COL_SIZE[0]:COL_SIZE[1]].strip()
        envelopes.append({
            "id": id_,
            "subject": subject,
            "from": sender,
            "date": date,
            "size": size,
        })
    return envelopes


def is_truncated(subject: str) -> bool:
    """Heuristic: heimdall caps SUBJECT at ~90 chars; if we filled the column,
    the row is almost certainly truncated mid-word."""
    return len(subject) >= 85


def fetch_full_subject(env_id: str) -> str | None:
    """Fetch the untruncated Subject via `himalaya message read <id>`."""
    result = subprocess.run(
        [str(HIMALAYA), "message", "read", env_id],
        capture_output=True, text=True, timeout=30,
    )
    if result.returncode != 0:
        return None
    for line in result.stdout.splitlines():
        if line.lower().startswith("subject:"):
            return line[8:].strip()
    return None


def fetch_envelopes(page: int = 1, page_size: int = 50,
                     untruncate: bool = True) -> list[dict]:
    """Fetch a page of envelopes, optionally filling in untruncated subjects."""
    result = subprocess.run(
        [str(HIMALAYA), "envelope", "list",
         "--page", str(page), "--page-size", str(page_size),
         "--max-width", "200"],
        capture_output=True, text=True, timeout=30,
    )
    if result.returncode != 0:
        return []
    envelopes = parse_envelope_table(result.stdout)

    if untruncate:
        for env in envelopes:
            if is_truncated(env["subject"]):
                full = fetch_full_subject(env["id"])
                if full:
                    env["subject"] = full
    return envelopes


if __name__ == "__main__":
    page = int(sys.argv[1]) if len(sys.argv) > 1 else 1
    page_size = int(sys.argv[2]) if len(sys.argv) > 2 else 50
    for env in fetch_envelopes(page=page, page_size=page_size):
        print(json.dumps(env, ensure_ascii=False))
