"""tunectl UI — Unicode banner and pipeline output in the opencode style.

Provides:
  - print_banner()   — block-letter "tunectl" banner with two-tone coloring
  - Pipeline context  — ┌/│/●/◇/▲/└ vertical status output

Style reference: opencode CLI (https://github.com/nicholasgriffintn/opencode)
  - First half "tune" rendered in dim gray  (ANSI 90)
  - Second half "ctl" rendered in bright white (ANSI 0/reset)
  - Hollow letter interiors use 256-color backgrounds (235/238)
  - Shadow accents on bottom row use fg 235
  - Pipeline uses box-drawing characters with double-space indent

Letter alphabet (4-wide cells, 4 rows each):
  Row 0 = top accent (only special letters like 'l' use ▄)
  Row 1 = upper body  (█▀▀█, █▀▀▄, █▀▀▀, etc.)
  Row 2 = middle body (█  █, █▀▀▀, █   , etc.)  — hollows get bg fill
  Row 3 = bottom      (▀▀▀▀, █▀▀▀, etc.)
"""

import sys

# ---------------------------------------------------------------------------
# ANSI helpers
# ---------------------------------------------------------------------------

def _use_color() -> bool:
    return sys.stdout.isatty()


def _esc(code: str) -> str:
    return f"\033[{code}m" if _use_color() else ""


R   = property(lambda self: _esc("0"))     # reset
DIM = property(lambda self: _esc("90"))    # dim gray

# We use module-level functions so the color check happens at call time.

def _r():
    return _esc("0")

def _d():
    return _esc("90")

def _bg_dim():
    return _esc("48;5;235")

def _bg_bright():
    return _esc("48;5;238")

def _fg_shadow():
    return _esc("38;5;235")

def _green():
    return _esc("32")

def _yellow():
    return _esc("33")

def _red():
    return _esc("31")

def _cyan():
    return _esc("36")


# ---------------------------------------------------------------------------
# Block-letter alphabet  (4 cols x 4 rows per glyph)
#
# Each letter is a tuple of 4 strings.  Characters:
#   █ = U+2588 full block      ▀ = U+2580 upper half
#   ▄ = U+2584 lower half      ' ' = space (hollow interior)
#
# Row 0 is the top-accent row (usually blank).
# Hollow interiors (spaces inside row 1-2) get background-color fills
# at render time — the alphabet stores plain spaces.
# ---------------------------------------------------------------------------

LETTERS = {
    "t": (
        "    ",
        "█▀▀█",
        "▀██▀",
        " ▀▀ ",
    ),
    "u": (
        "    ",
        "█  █",
        "█  █",
        "▀▀▀█",
    ),
    "n": (
        "    ",
        "█▀▀▄",
        "█  █",
        "▀  ▀",
    ),
    "e": (
        "    ",
        "█▀▀█",
        "█▀▀▀",
        "▀▀▀▀",
    ),
    "c": (
        "    ",
        "█▀▀▀",
        "█   ",
        "▀▀▀▀",
    ),
    "l": (
        "   ▄",
        "█▀▀█",
        "█  █",
        "▀▀▀▀",
    ),
}

# ---------------------------------------------------------------------------
# Banner renderer
# ---------------------------------------------------------------------------

# "tune" = dim half, "ctl" = bright half
_DIM_LETTERS = "tune"
_BRIGHT_LETTERS = "ctl"
_WORD = _DIM_LETTERS + _BRIGHT_LETTERS  # "tunectl"


def _render_char(ch: str, fg_fn, bg_fn, shadow_fn, row: int) -> str:
    """Render one character of a letter cell with proper ANSI coloring.

    fg_fn    — returns the foreground escape for solid glyphs (█ ▀ ▄)
    bg_fn    — returns the background escape for hollow interiors (spaces)
    shadow_fn — returns the fg escape for shadow accents on the bottom row
    row      — which row (0-3) we are rendering
    """
    r = _r()

    if ch == " ":
        # Hollow interior — fill with background color (rows 1-2 only)
        if row in (1, 2):
            return f"{bg_fn()}{ch}{r}"
        return ch

    if ch == "▀" and row == 3:
        # Bottom row: check if this is an interior accent (shadow)
        # We handle this at a higher level; default to fg
        return f"{fg_fn()}{ch}{r}"

    # Solid glyph
    return f"{fg_fn()}{ch}{r}"


def _render_row(row_idx: int) -> str:
    """Render one row of the full 'tunectl' banner."""
    r = _r()
    parts = []

    for i, letter_ch in enumerate(_WORD):
        glyph = LETTERS[letter_ch]
        row_str = glyph[row_idx]

        if letter_ch in _DIM_LETTERS and _WORD.index(letter_ch) == i and i < len(_DIM_LETTERS):
            fg_fn = _d
            bg_fn = _bg_dim
            shadow_fn = _fg_shadow
        elif i >= len(_DIM_LETTERS):
            fg_fn = _r
            bg_fn = _bg_bright
            shadow_fn = _r
        else:
            # Duplicate letter in dim section
            fg_fn = _d
            bg_fn = _bg_dim
            shadow_fn = _fg_shadow

        cell = ""
        for j, ch in enumerate(row_str):
            if ch == " " and row_idx in (1, 2):
                cell += f"{bg_fn()}{ch}{_r()}"
            elif ch == "▀" and row_idx == 3:
                # Shadow: inner chars of dim-half bottom row get subtle shadow
                if fg_fn == _d and 0 < j < 3:
                    cell += f"{shadow_fn()}{ch}{_r()}"
                else:
                    cell += f"{fg_fn()}{ch}{_r()}"
            else:
                if ch == " ":
                    cell += ch
                else:
                    cell += f"{fg_fn()}{ch}{_r()}"

        parts.append(cell)

    return "  " + " ".join(parts)


def banner() -> str:
    """Return the full tunectl banner string (4 rows + surrounding newlines)."""
    lines = [""]
    for row_idx in range(4):
        lines.append(_render_row(row_idx))
    lines.append("")
    return "\n".join(lines)


def print_banner() -> None:
    """Print the tunectl banner to stdout."""
    print(banner())


# ---------------------------------------------------------------------------
# Pipeline output  (┌ │ ● ◇ ▲ └)
# ---------------------------------------------------------------------------

_SYM_START  = "\u250C"  # ┌
_SYM_PIPE   = "\u2502"  # │
_SYM_DOT    = "\u25CF"  # ●
_SYM_OK     = "\u25C7"  # ◇
_SYM_WARN   = "\u25B2"  # ▲
_SYM_END    = "\u2514"  # └


class Pipeline:
    """Context-manager for styled vertical pipeline output.

    Usage:
        with Pipeline("Discover") as p:
            p.step("OS: Ubuntu 24.04 LTS")
            p.step("Kernel: 6.8.0-101-generic")
            p.ok("Discovery complete")
    """

    def __init__(self, title: str, show_banner: bool = True):
        self.title = title
        self.show_banner = show_banner
        self._started = False

    def __enter__(self):
        if self.show_banner:
            print_banner()
        print(f"{_SYM_START}  {self.title}")
        self._started = True
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type is not None:
            self.fail(f"Error: {exc_val}")
        self._end()
        return False

    def _line(self):
        print(_SYM_PIPE)

    def step(self, msg: str) -> None:
        self._line()
        c = _cyan() if _use_color() else ""
        r = _r() if _use_color() else ""
        print(f"{_SYM_DOT}  {msg}")

    def ok(self, msg: str) -> None:
        self._line()
        g = _green() if _use_color() else ""
        r = _r() if _use_color() else ""
        print(f"{g}{_SYM_OK}{r}  {msg}")

    def warn(self, msg: str) -> None:
        self._line()
        y = _yellow() if _use_color() else ""
        r = _r() if _use_color() else ""
        print(f"{y}{_SYM_WARN}{r}  {msg}")

    def fail(self, msg: str) -> None:
        self._line()
        rd = _red() if _use_color() else ""
        r = _r() if _use_color() else ""
        print(f"{rd}{_SYM_DOT}{r}  {msg}")

    def _end(self) -> None:
        self._line()
        print(f"{_SYM_END}  Done")
        print()
