#!/usr/bin/env python3
"""List windows visible to AT-SPI accessibility tree.

Usage:
    list-windows.py [--json] [--verbose]

Options:
    --json      Output as JSON
    --verbose   Include child element counts
"""

import argparse
import json
import sys

import pyatspi

from common import set_debug, log_debug


def get_window_info(window, verbose=False):
    """Extract info from a window accessible."""
    info = {
        "name": window.name or "(unnamed)",
        "role": window.getRoleName(),
    }

    # Get state
    state = window.getState()
    states = []
    for s in pyatspi.STATE_VALUE_TO_NAME:
        if state.contains(s):
            states.append(pyatspi.STATE_VALUE_TO_NAME[s])
    info["states"] = states

    # Get position/size if available
    try:
        component = window.queryComponent()
        if component:
            rect = component.getExtents(pyatspi.DESKTOP_COORDS)
            info["geometry"] = {
                "x": rect.x,
                "y": rect.y,
                "width": rect.width,
                "height": rect.height,
            }
    except Exception as e:
        log_debug(f"Failed to get geometry for {info['name']}: {e}")

    if verbose:
        # Count children recursively (expensive)
        def count_children(acc, path=""):
            try:
                count = acc.childCount
                for i in range(acc.childCount):
                    child = acc.getChildAtIndex(i)
                    if child:
                        count += count_children(child, f"{path}/{i}")
                return count
            except Exception as e:
                log_debug(f"Error counting children at {path}: {e}")
                return 0
        info["child_count"] = count_children(window, info["name"])

    return info


def list_windows(verbose=False):
    """Get all windows from AT-SPI desktop."""
    desktop = pyatspi.Registry.getDesktop(0)

    apps = []
    for i in range(desktop.childCount):
        app = desktop.getChildAtIndex(i)
        if not app:
            continue

        app_info = {
            "name": app.name or "(unnamed)",
            "windows": [],
        }

        for j in range(app.childCount):
            window = app.getChildAtIndex(j)
            if window:
                window_info = get_window_info(window, verbose)
                app_info["windows"].append(window_info)

        if app_info["windows"]:  # Only include apps with windows
            apps.append(app_info)

    return apps


def print_table(apps):
    """Print apps/windows as formatted table."""
    if not apps:
        print("No windows found via AT-SPI.")
        print("\nTips:")
        print("  - Apps started before AT-SPI enablement won't register")
        print("  - GTK/Qt apps should work; Electron varies")
        print("  - Try: accerciser (GUI) to explore the tree")
        return

    for app in apps:
        print(f"\n{app['name']}")
        print("-" * len(app["name"]))
        for win in app["windows"]:
            geo = win.get("geometry", {})
            geo_str = f"{geo.get('width', '?')}x{geo.get('height', '?')}" if geo else ""
            states_str = ", ".join(win.get("states", [])[:3])  # First 3 states

            line = f"  [{win['role']}] {win['name']}"
            if geo_str:
                line += f"  ({geo_str})"
            if states_str:
                line += f"  [{states_str}]"
            if "child_count" in win:
                line += f"  ({win['child_count']} elements)"
            print(line)


def main():
    parser = argparse.ArgumentParser(description="List AT-SPI accessible windows")
    parser.add_argument("--json", action="store_true", help="Output as JSON")
    parser.add_argument("--verbose", "-v", action="store_true",
                        help="Include child element counts (slower)")
    parser.add_argument("--debug", action="store_true",
                        help="Show debug messages for AT-SPI errors")
    args = parser.parse_args()

    if args.debug:
        set_debug(True)

    try:
        apps = list_windows(verbose=args.verbose)
    except Exception as e:
        print(f"Error accessing AT-SPI: {e}", file=sys.stderr)
        print("\nIs AT-SPI enabled?", file=sys.stderr)
        print("  Check: dbus-send --session --dest=org.a11y.Bus --print-reply /org/a11y/bus org.freedesktop.DBus.Peer.Ping", file=sys.stderr)
        sys.exit(1)

    if args.json:
        print(json.dumps(apps, indent=2))
    else:
        print_table(apps)


if __name__ == "__main__":
    main()
