#!/usr/bin/env python3
"""
Smoke test: construct :class:`fiwi.concentrator.FiWiConcentrator`, then print Adnacom host-card
catalog, local USB power-control hubs (``show_hostcards``), and **remote** hub hosts from
``[remote_hubs]`` / ``FIWI_REMOTE_HUBS`` (each probed with ``ssh … show_hostcards`` when possible).

Requires the BrainStem Python package (``brainstem`` in requirements.txt). USB discovery may print
“no link specs” if no compatible hubs are attached — that is normal off the bench. Remote SSH must
reach the Pi (or host) where ``fiwi.py`` and BrainStem are installed.

**Standalone** (any current working directory)::

    python tests/check_concentrator.py
    python tests/check_concentrator.py --config uax24
    python tests/check_concentrator.py -c uax4
    python tests/check_concentrator.py --config /path/to/custom.ini

``--config`` is the same as ``FIWI_CONFIG``: a profile name (``config/<name>.ini``) or an absolute path to a ``.ini`` file.

With pytest, set the profile in the environment (argv is not parsed)::

    FIWI_CONFIG=uax24 pytest tests/check_concentrator.py
"""

from __future__ import annotations

import argparse
import os
import sys
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from fiwi.concentrator import FiWiConcentrator

_ROOT = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
if _ROOT not in sys.path:
    sys.path.insert(0, _ROOT)

_paths_configured = False


def _ensure_paths_configured() -> None:
    """Apply ``fiwi.paths.configure`` once (after ``FIWI_CONFIG`` is set for script runs)."""
    global _paths_configured
    if _paths_configured:
        return
    import fiwi.paths as paths_mod

    paths_mod.configure(_ROOT)
    _paths_configured = True


def _instantiate_concentrator() -> FiWiConcentrator:
    _ensure_paths_configured()
    from fiwi.concentrator import FiWiConcentrator

    c = FiWiConcentrator()
    assert c.hubs == [], "new concentrator should have no connected hubs yet"
    return c


def _print_remote_hub_hostcards() -> None:
    """List configured remote hub SSH targets and run ``show_hostcards`` on each (if any)."""
    from fiwi.ssh import SshNode, SshNodeConfig

    cfg = SshNodeConfig.load()
    raw = (cfg.calibrate_remotes or "").strip()
    rh_only = (os.environ.get("FIWI_REMOTE_HUBS") or "").strip()
    cr_only = (os.environ.get("FIWI_CALIBRATE_REMOTES") or "").strip()

    print("Remote hub hosts (from config)", flush=True)
    print("-" * 60, flush=True)
    if not raw:
        print(
            "  (none)  — set [remote_hubs] hosts or remote_ssh.calibrate_remotes in config/*.ini,\n"
            "            or FIWI_REMOTE_HUBS / FIWI_CALIBRATE_REMOTES in the environment.",
            flush=True,
        )
        print("-" * 60, flush=True)
        print()
        return

    if rh_only:
        print(f"  FIWI_REMOTE_HUBS: {rh_only}", flush=True)
    if cr_only:
        print(f"  FIWI_CALIBRATE_REMOTES: {cr_only}", flush=True)
    print(f"  merged for calibrate: {raw}", flush=True)
    print("-" * 60, flush=True)

    seen: list[str] = []
    for part in raw.split(","):
        host = part.strip()
        if not host or host in seen:
            continue
        seen.append(host)
        print(f"\nRemote USB power-control hubs via SSH → {host}\n", flush=True)
        try:
            node = SshNode.parse(host)
            code, out, err = node.invoke_capture(["show_hostcards"], timeout=90, defer=False)
            if out.strip():
                print(out.rstrip(), flush=True)
            if err.strip():
                print(err.rstrip(), file=sys.stderr, flush=True)
            if code != 0:
                print(f"  (remote show_hostcards exit {code})", flush=True)
        except Exception as exc:
            print(f"  SSH / remote run failed: {exc}", flush=True)
    print()


def _print_inventory(c: FiWiConcentrator) -> None:
    """Adnacom PCIe catalog + local and remote USB power-control hub views."""
    from fiwi.adnacom_pcie_catalog import print_adnacom_host_card_table

    print()
    print_adnacom_host_card_table()
    print()
    print("USB power-control hubs — local (hostcards)", flush=True)
    c.show_hostcards()
    print()
    _print_remote_hub_hostcards()


def test_concentrator() -> None:
    c = _instantiate_concentrator()
    c.disconnect()


def _parse_args() -> argparse.Namespace:
    p = argparse.ArgumentParser(
        description="Smoke test: instantiate FiWiConcentrator using a config profile.",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog=(
            "PROFILE selects <repo>/config/<PROFILE>.ini (e.g. uax24, uax4, default).\n"
            "An absolute path to a .ini file is used as-is.\n"
            "Same as environment variable FIWI_CONFIG."
        ),
    )
    p.add_argument(
        "-c",
        "--config",
        metavar="PROFILE_OR_INI",
        help="INI profile or absolute path (sets FIWI_CONFIG for this run)",
    )
    return p.parse_args()


def main() -> int:
    try:
        os.chdir(_ROOT)
    except OSError as exc:
        print(f"FAIL: cannot chdir to repo root {_ROOT!r}: {exc}", file=sys.stderr)
        return 1
    args = _parse_args()
    if args.config:
        os.environ["FIWI_CONFIG"] = args.config.strip()
    c = None
    try:
        c = _instantiate_concentrator()
        _print_inventory(c)
    except AssertionError as exc:
        print(f"FAIL: {exc}", file=sys.stderr)
        return 1
    except Exception as exc:
        print(f"FAIL: {exc}", file=sys.stderr)
        return 1
    finally:
        if c is not None:
            try:
                c.disconnect()
            except Exception:
                pass
    label = os.environ.get("FIWI_CONFIG", "default (config/default.ini if present)")
    print(f"FiWiConcentrator() OK  [config: {label}]")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
