#!/usr/bin/env python3
"""Parse a man page and output a compact options chart."""

import re
import subprocess
import sys
import shutil


def get_man_text(command):
    """Get plain-text man page content (no MANWIDTH override — preserve native layout)."""
    result = subprocess.run(
        ["man", command], capture_output=True, text=True,
    )
    if result.returncode != 0:
        print(f"No man page found for '{command}'", file=sys.stderr)
        sys.exit(1)
    # Strip backspace-based formatting only, preserve tabs
    cleaned = subprocess.run(
        ["col", "-b"], input=result.stdout, capture_output=True, text=True,
    )
    return cleaned.stdout


def extract_options_section(text):
    """Pull out the section(s) containing flag definitions.

    Strategy: find all section boundaries first, then prefer dedicated option
    sections. Fall back to DESCRIPTION only if nothing better exists.
    """
    lines = text.splitlines()
    header_re = re.compile(r'^[A-Z][A-Z /()-]+$')

    # 1. Map section names → (start_line, end_line) ranges
    sections = []
    for i, line in enumerate(lines):
        stripped = line.strip()
        if header_re.match(stripped) and len(stripped) > 2:
            sections.append((stripped, i))

    # Build ranges: each section goes from its header+1 to the next header
    section_ranges = {}
    for idx, (name, start) in enumerate(sections):
        end = sections[idx + 1][1] if idx + 1 < len(sections) else len(lines)
        if name not in section_ranges:
            section_ranges[name] = []
        section_ranges[name].append((start + 1, end))

    # 2. Prefer explicit option sections, fall back to DESCRIPTION
    preferred = ["ALL OPTIONS", "OPTIONS", "COMMAND OPTIONS",
                 "GENERAL OPTIONS", "GLOBAL OPTIONS", "COMMON OPTIONS"]
    fallback = ["DESCRIPTION"]

    result = []
    for name in preferred:
        if name in section_ranges:
            for start, end in section_ranges[name]:
                result.extend(lines[start:end])

    if not result:
        for name in fallback:
            if name in section_ranges:
                for start, end in section_ranges[name]:
                    result.extend(lines[start:end])

    return result


def parse_options(section_lines):
    """Parse option entries from section lines.

    Man page option layouts:
      A)  "       -a, --all"          flags on own line
          "\\t      description"       tab-indented description follows
      B)  "       -c     desc text"   short flag + inline description (no --long form)
          "\\t      continuation"      tab-indented continuation
    """
    entries = []
    current_flags = None
    current_desc_lines = []

    # Option line: SPACES (not tabs) then a dash — real option definitions
    opt_line = re.compile(r'^( {4,12})(-.+)$')
    # Tab-indented description/continuation line
    desc_line = re.compile(r'^[\t][\t ]*(\S.*)$')

    # Extract flag portion, then anything remaining is inline description.
    #   "-c     with -lt:..."      →  flags="-c",             desc="with -lt:..."
    #   "-a, --all"                →  flags="-a, --all",      desc=""
    #   "--zero end each..."       →  flags="--zero",         desc="end each..."
    #   "--color[=WHEN]"           →  flags="--color[=WHEN]", desc=""
    flag_extract = re.compile(
        r'^('
        r'-\w(?:,\s+--[^\s]+)?'   # -X  or  -X, --long-form[=ARG]
        r'|'
        r'--[^\s]+'               # --long-form[=ARG]
        r')'
        r'(?:\s+(.+))?$'          # optional inline description
    )

    def flush():
        if current_flags is not None:
            desc = " ".join(current_desc_lines).strip()
            entries.append((current_flags.strip(), desc))

    for line in section_lines:
        om = opt_line.match(line)
        dm = desc_line.match(line)

        if om:
            flush()
            raw = om.group(2).strip()
            # Split flag from any inline description
            fm = flag_extract.match(raw)
            if fm:
                current_flags = fm.group(1)
                current_desc_lines = [fm.group(2)] if fm.group(2) else []
            else:
                current_flags = raw
                current_desc_lines = []
        elif dm and current_flags is not None:
            current_desc_lines.append(dm.group(1))
        # Skip blank lines and non-option prose silently

    flush()

    # Clean up and deduplicate entries.
    cleaned = []
    seen = set()
    for flags, desc in entries:
        # Strip trailing punctuation from flags (prose lists like "--rate, --show-error")
        canon = flags.rstrip(".,;:")
        # Skip entries with empty canonical flag or already seen
        if not canon or canon in seen:
            continue
        seen.add(canon)
        cleaned.append((canon, desc))

    return cleaned



def build_table(command, entries, max_width):
    """Format entries into a compact table."""
    if not entries:
        print(f"No options found for '{command}'.")
        return

    # Calculate column widths
    flag_width = min(max(len(e[0]) for e in entries), 34)
    desc_width = max_width - flag_width - 7  # borders + padding

    header = f"  {command} options"
    sep = "─"

    lines = []
    lines.append(f"┌{'─' * (max_width - 2)}┐")
    lines.append(f"│{header:^{max_width - 2}}│")
    lines.append(f"├{'─' * (flag_width + 2)}┬{'─' * (desc_width + 2)}┤")

    for flags, desc in entries:
        # Truncate description if needed
        if len(desc) > desc_width:
            desc = desc[:desc_width - 1] + "…"
        # Truncate flags if needed
        if len(flags) > flag_width:
            flags = flags[:flag_width - 1] + "…"
        lines.append(f"│ {flags:<{flag_width}} │ {desc:<{desc_width}} │")

    lines.append(f"└{'─' * (flag_width + 2)}┴{'─' * (desc_width + 2)}┘")

    print("\n".join(lines))


def main():
    if len(sys.argv) < 2:
        print(f"Usage: {sys.argv[0]} <command>", file=sys.stderr)
        sys.exit(1)

    command = sys.argv[1]
    term_width = min(shutil.get_terminal_size((120, 24)).columns, 140)

    text = get_man_text(command)
    section = extract_options_section(text)

    if not section:
        # Some man pages put options in DESCRIPTION (like ls)
        # Fall back to scanning the whole page
        section = text.splitlines()

    entries = parse_options(section)

    if not entries:
        print(f"Could not parse options from man page for '{command}'.", file=sys.stderr)
        sys.exit(1)

    build_table(command, entries, term_width)


if __name__ == "__main__":
    main()
