from __future__ import annotations

import sys
from typing import Any, Dict, Iterable, Sequence

from . import _shared as sh
from SYS.logger import log
from SYS import pipeline as ctx

from SYS.result_table_adapters import get_plugin
from SYS.result_table_renderers import RichRenderer

Cmdlet = sh.Cmdlet
CmdletArg = sh.CmdletArg
parse_cmdlet_args = sh.parse_cmdlet_args


CMDLET = Cmdlet(
    name="plugin-table",
    summary="Render a plugin's result set and optionally run a follow-up cmdlet using the selected row.",
    usage="plugin-table -plugin <name> [-sample] [-select <n>] [-run-cmd <name>]",
    arg=[
        CmdletArg("plugin", type="string", description="Plugin name to render (default: example)"),
        CmdletArg("sample", type="flag", description="Use plugin sample/demo items when available."),
        CmdletArg("select", type="int", description="1-based row index to select and use for follow-up command."),
        CmdletArg("run-cmd", type="string", description="Cmdlet to invoke with the selected row's selector args."),
    ],
    detail=[
        "Use a registered plugin to build a table and optionally run another cmdlet with selection args.",
        "Emits pipeline-friendly dicts enriched with `_selection_args` so you can use @N syntax to select and chain.",
        "Example: plugin-table -plugin example -sample | @1 | add-file -instance my_store",
    ],
)


def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
    parsed = parse_cmdlet_args(args, CMDLET)

    plugin_name = parsed.get("plugin") or "example"
    use_sample = bool(parsed.get("sample", False))
    run_cmd = parsed.get("run-cmd")
    select_raw = parsed.get("select")

    try:
        plugin = get_plugin(plugin_name)
    except Exception:
        log(f"Unknown plugin: {plugin_name}", file=sys.stderr)
        return 1

    # Obtain items to feed to the adapter
    items = None
    if use_sample:
        # Try to locate SAMPLE_ITEMS in the adapter's module (convention only)
        try:
            mod = __import__(plugin.adapter.__module__, fromlist=["*"])
            items = getattr(mod, "SAMPLE_ITEMS", None)
            if items is None:
                log("Plugin does not expose SAMPLE_ITEMS; no sample available", file=sys.stderr)
                return 1
        except Exception:
            log("Failed to load plugin sample", file=sys.stderr)
            return 1
    else:
        # Require input for non-sample runs
        inputs = list(result) if isinstance(result, Iterable) else []
        if not inputs:
            log("No input provided. Use -sample for demo or pipe plugin items in.", file=sys.stderr)
            return 1
        items = inputs

    try:
        table = plugin.build_table(items)
    except Exception as exc:
        log(f"Plugin '{plugin.name}' failed: {exc}", file=sys.stderr)
        return 1

    # Emit rows for downstream pipeline consumption (pipable behavior).
    try:
        for item in plugin.serialize_rows(table.rows):
            try:
                ctx.emit(item)
            except Exception:
                continue
    except Exception:
        # Non-fatal: rendering still happens
        pass

    # Render using RichRenderer
    try:
        renderable = RichRenderer().render(table.rows, table.columns, table.meta)
        try:
            from rich.console import Console

            Console().print(renderable)
        except Exception:
            # Fallback to simple printing
            for r in table.rows:
                print(" ".join(str((c.extractor(r) or "")) for c in table.columns))
    except Exception as exc:
        log(f"Rendering failed: {exc}", file=sys.stderr)
        return 1

    # If no selection requested, we're done
    if not select_raw:
        return 0

    try:
        select_idx = int(select_raw) - 1
    except Exception:
        log("Invalid -select value; must be an integer", file=sys.stderr)
        return 1

    if select_idx < 0 or select_idx >= len(table.rows):
        log("-select out of range", file=sys.stderr)
        return 1

    selected = table.rows[select_idx]
    sel_args = plugin.selection_args(selected)

    if not run_cmd:
        # Print selection args for caller
        log(f"Selection args: {sel_args}", file=sys.stderr)
        return 0

    # Run follow-up cmdlet
    try:
        from cmdlet import ensure_cmdlet_modules_loaded, get as get_cmdlet

        ensure_cmdlet_modules_loaded()
        cmd_fn = get_cmdlet(run_cmd)
        if not cmd_fn:
            log(f"Follow-up cmdlet not found: {run_cmd}", file=sys.stderr)
            return 1

        # Call the cmdlet with no upstream result, but with selection args
        ret = cmd_fn(None, sel_args, config or {})
        return ret
    except Exception as exc:
        log(f"Failed to invoke follow-up cmdlet: {exc}", file=sys.stderr)
        return 1


CMDLET.exec = _run
CMDLET.register()
