from __future__ import annotations

import os
import re
import sys
from pathlib import Path
from typing import Any, Dict, Sequence, Optional

from cmdlet._shared import Cmdlet, CmdletArg
from SYS.logger import log
from SYS import pipeline as ctx

CMDLET = Cmdlet(
    name=".out-table",
    summary="Save the current result table to an SVG file.",
    usage='.out-table -path "C:\\Path\\To\\Dir"',
    arg=[
        CmdletArg(
            "path",
            type="string",
            description="Directory (or file path) to write the SVG to",
            required=True,
        ),
    ],
    detail=[
        "Exports the most recent table (overlay/stage/last) as an SVG using Rich.",
        "Default filename is derived from the table title (sanitized).",
        "Examples:",
        'search-file "ext:mp3" | .out-table -path "C:\\Users\\Admin\\Desktop"',
        'search-file "ext:mp3" | .out-table -path "C:\\Users\\Admin\\Desktop\\my-table.svg"',
    ],
)

_WINDOWS_RESERVED_NAMES = {
    "con",
    "prn",
    "aux",
    "nul",
    *(f"com{i}" for i in range(1, 10)),
    *(f"lpt{i}" for i in range(1, 10)),
}


def _sanitize_filename_base(text: str) -> str:
    """Sanitize a string for use as a Windows-friendly filename (no extension)."""
    s = str(text or "").strip()
    if not s:
        return "table"

    # Replace characters illegal on Windows (and generally unsafe cross-platform).
    s = re.sub(r'[<>:"/\\|?*]', " ", s)

    # Drop control characters.
    s = "".join(ch for ch in s if ch.isprintable())

    # Collapse whitespace.
    s = " ".join(s.split()).strip()

    # Windows disallows trailing space/dot.
    s = s.rstrip(" .")

    if not s:
        s = "table"

    # Avoid reserved device names.
    if s.lower() in _WINDOWS_RESERVED_NAMES:
        s = f"_{s}"

    # Keep it reasonably short.
    if len(s) > 200:
        s = s[:200].rstrip(" .")

    return s or "table"


def _resolve_output_path(path_arg: str, *, table_title: str) -> Path:
    raw = str(path_arg or "").strip()
    if not raw:
        raise ValueError("-path is required")

    # Treat trailing slash as directory intent even if it doesn't exist yet.
    ends_with_sep = raw.endswith((os.sep, os.altsep or ""))

    target = Path(raw)

    if target.exists() and target.is_dir():
        base = _sanitize_filename_base(table_title)
        return target / f"{base}.svg"

    if ends_with_sep and not target.suffix:
        target.mkdir(parents=True, exist_ok=True)
        base = _sanitize_filename_base(table_title)
        return target / f"{base}.svg"

    # File path intent.
    if not target.suffix:
        return target.with_suffix(".svg")

    if target.suffix.lower() != ".svg":
        return target.with_suffix(".svg")

    return target


def _get_active_table(piped_result: Any) -> Optional[Any]:
    # Prefer an explicit ResultTable passed through the pipe, but normally `.out-table`
    # is used after `@` which pipes item selections (not the table itself).
    if piped_result is not None and hasattr(piped_result, "__rich__"):
        # Avoid mistakenly treating a dict/list as a renderable.
        if piped_result.__class__.__name__ == "ResultTable":
            return piped_result

    return ctx.get_display_table() or ctx.get_current_stage_table(
    ) or ctx.get_last_result_table()


def _run(piped_result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
    args_list = [str(a) for a in (args or [])]

    # Simple flag parsing: `.out-table -path <value>`
    path_arg: Optional[str] = None
    i = 0
    while i < len(args_list):
        low = args_list[i].strip().lower()
        if low in {"-path",
                   "--path"} and i + 1 < len(args_list):
            path_arg = args_list[i + 1]
            i += 2
            continue
        if not args_list[i].startswith("-") and path_arg is None:
            # Allow `.out-table <path>` as a convenience.
            path_arg = args_list[i]
        i += 1

    if not path_arg:
        log("Missing required -path", file=sys.stderr)
        return 1

    table = _get_active_table(piped_result)
    if table is None:
        log("No table available to export", file=sys.stderr)
        return 1

    title = getattr(table, "title", None)
    title_text = str(title or "table")

    try:
        out_path = _resolve_output_path(path_arg, table_title=title_text)
        out_path.parent.mkdir(parents=True, exist_ok=True)

        from rich.console import Console

        console = Console(record=True)
        console.print(table)
        console.save_svg(str(out_path))

        log(f"Saved table SVG: {out_path}")
        return 0
    except Exception as exc:
        log(f"Failed to save table SVG: {type(exc).__name__}: {exc}", file=sys.stderr)
        return 1


CMDLET.exec = _run
