"""
Terminal display utilities — colors, formatting, tables.
Datanaut theme: space explorer navigating the data galaxy.
"""

import sys
import time
import threading
import itertools
import random

# ANSI color codes
RESET   = "\033[0m"
BOLD    = "\033[1m"
DIM     = "\033[2m"
CYAN    = "\033[36m"
GREEN   = "\033[32m"
YELLOW  = "\033[33m"
RED     = "\033[31m"
BLUE    = "\033[34m"
MAGENTA = "\033[35m"
WHITE   = "\033[97m"

# Extra ANSI
BRIGHT_CYAN    = "\033[96m"
BRIGHT_YELLOW  = "\033[93m"
BRIGHT_GREEN   = "\033[92m"
BRIGHT_MAGENTA = "\033[95m"
BRIGHT_BLUE    = "\033[94m"

# ── Spinner state ─────────────────────────────────────────────────────────────

_spinner_active = False
_spinner_thread = None


def _spin(label: str):
    """Background thread that renders an animated datanaut spinner."""
    frames = [
        f"{BRIGHT_CYAN}🛸{RESET}",
        f"{BRIGHT_CYAN} 🛸{RESET}",
        f"{BRIGHT_CYAN}  🛸{RESET}",
        f"{BRIGHT_CYAN} 🛸{RESET}",
    ]
    orbit = itertools.cycle(frames)
    stars = ["·", "✦", "·", "✧", "·", "✦"]
    star_cycle = itertools.cycle(stars)
    while _spinner_active:
        frame = next(orbit)
        star  = next(star_cycle)
        sys.stdout.write(f"\r  {frame}  {DIM}{star}{RESET}  {CYAN}{label}{RESET}   ")
        sys.stdout.flush()
        time.sleep(0.12)
    sys.stdout.write("\r" + " " * (len(label) + 20) + "\r")
    sys.stdout.flush()


def start_spinner(label: str):
    global _spinner_active, _spinner_thread
    _spinner_active = True
    _spinner_thread = threading.Thread(target=_spin, args=(label,), daemon=True)
    _spinner_thread.start()


def stop_spinner():
    global _spinner_active
    _spinner_active = False
    if _spinner_thread:
        _spinner_thread.join()


# ── Banner ────────────────────────────────────────────────────────────────────

def print_banner():
    # Star row width matches the banner width exactly (74 visible chars)
    star_row = f"{BRIGHT_CYAN}  ✦ · ✧ · ✦ · ✧ · ✦ · ✧ · ✦ · ✧ · ✦ · ✧ · ✦ · ✧ · ✦ · ✧{RESET}"

    # Full DATANAUT in one continuous pixel row per line.
    # DATA (cyan→dim-cyan) + NAUT (bright-magenta→magenta) joined with no gap.
    # Every line is exactly the same visible width.
    C1, C2 = BRIGHT_CYAN, CYAN          # cyan gradient top→bottom
    M1, M2 = BRIGHT_MAGENTA, MAGENTA    # magenta gradient top→bottom
    R       = RESET

    rows = [
        f"{C1}  ██████╗  █████╗ ████████╗ █████╗ {R}{M1}███╗   ██╗ █████╗ ██╗   ██╗████████╗{R}",
        f"{C1}  ██╔══██╗██╔══██╗╚══██╔══╝██╔══██╗{R}{M1}████╗  ██║██╔══██╗██║   ██║╚══██╔══╝{R}",
        f"{C1}  ██║  ██║███████║   ██║   ███████║{R}{M1}██╔██╗ ██║███████║██║   ██║   ██║   {R}",
        f"{C2}  ██║  ██║██╔══██║   ██║   ██╔══██║{R}{M2}██║╚██╗██║██╔══██║██║   ██║   ██║   {R}",
        f"{C2}  ██████╔╝██║  ██║   ██║   ██║  ██║{R}{M2}██║ ╚████║██║  ██║╚██████╔╝   ██║   {R}",
        f"{C2}  ╚═════╝ ╚═╝  ╚═╝   ╚═╝   ╚═╝  ╚═╝{R}{M2}╚═╝  ╚═══╝╚═╝  ╚═╝ ╚═════╝    ╚═╝  {R}",
    ]

    subtitle = (
        f"  {DIM}{CYAN}🚀  SQL Explorer v1.0"
        f"  ·  Navigating the BigQuery galaxy...{RESET}"
    )

    print()
    print(star_row)
    print()
    for line in rows:
        print(line)
        time.sleep(0.05)
    print()
    print(subtitle)
    print()
    print(star_row)
    print()


# ── Step indicator ────────────────────────────────────────────────────────────

_STEP_ICONS = {
    "schema":   f"{BRIGHT_YELLOW}🗺️ {RESET}",
    "generat":  f"{BRIGHT_CYAN}🤖{RESET}",
    "dry run":  f"{BRIGHT_MAGENTA}⚗️ {RESET}",
    "retry":    f"{YELLOW}🔄{RESET}",
    "execut":   f"{BRIGHT_GREEN}🚀{RESET}",
    "cache":    f"{CYAN}💾{RESET}",
    "default":  f"{CYAN}⚡{RESET}",
}


def print_step(message: str):
    msg_lower = message.lower()
    icon = _STEP_ICONS["default"]
    for key, val in _STEP_ICONS.items():
        if key in msg_lower:
            icon = val
            break
    print(f"  {icon}  {DIM}{message}{RESET}")


# ── SQL display ───────────────────────────────────────────────────────────────

def print_sql(sql: str):
    lines = sql.strip().split("\n")

    # Measure the longest raw line (no ANSI codes) + 4 chars padding (2 left, 2 right)
    max_len = max((len(line) for line in lines), default=40)
    box_w   = max(max_len + 4, 40)   # minimum 40, grows with content

    # Box borders sized to content
    header    = f"{BRIGHT_CYAN}╔{'═' * box_w}╗{RESET}"
    divider   = f"{BRIGHT_CYAN}╠{'═' * box_w}╣{RESET}"
    footer    = f"{BRIGHT_CYAN}╚{'═' * box_w}╝{RESET}"
    # Avoid emoji in title — emoji render as 2 terminal columns but len() counts 1,
    # causing the right border to shift right by 1. Use plain ASCII symbols instead.
    title_txt = "  >>  MISSION QUERY"
    title_pad = " " * (box_w - len(title_txt))
    title     = f"{BRIGHT_CYAN}║{RESET}{BOLD}{BRIGHT_YELLOW}{title_txt}{title_pad}{RESET}{BRIGHT_CYAN}║{RESET}"

    print(f"\n{header}")
    print(title)
    print(divider)

    # Syntax-highlight keywords
    keywords = [
        "SELECT", "FROM", "WHERE", "GROUP BY", "ORDER BY", "LIMIT",
        "JOIN", "LEFT JOIN", "INNER JOIN", "WITH", "AS", "ON",
        "HAVING", "UNION", "AND", "OR", "NOT", "IN", "BETWEEN",
        "DATE", "DATETIME", "TIMESTAMP", "COUNT", "SUM", "AVG",
        "MAX", "MIN", "DISTINCT", "CASE", "WHEN", "THEN", "ELSE", "END",
    ]

    for line in lines:
        highlighted = line
        for kw in keywords:
            highlighted = highlighted.replace(
                f" {kw} ", f" {BRIGHT_YELLOW}{kw}{RESET}{CYAN} "
            ).replace(
                f"\t{kw} ", f"\t{BRIGHT_YELLOW}{kw}{RESET}{CYAN} "
            )
            if highlighted.strip().startswith(kw):
                highlighted = f"{BRIGHT_YELLOW}{kw}{RESET}{CYAN}" + highlighted[len(kw):]

        # Compute visible terminal width of the raw line.
        # Emoji & CJK chars are 2 columns wide; wcwidth handles this correctly.
        try:
            import wcwidth
            vis_len = wcwidth.wcswidth(line)
            if vis_len < 0:
                vis_len = len(line)
        except ImportError:
            vis_len = len(line)

        right_pad = " " * max(box_w - vis_len - 2, 0)
        print(f"{BRIGHT_CYAN}║{RESET}  {CYAN}{highlighted}{RESET}{right_pad}{BRIGHT_CYAN}║{RESET}")

    print(footer)
    print()


# ── Animated thinking dots ────────────────────────────────────────────────────

def thinking_animation(label: str = "Contacting mission control", duration: float = 1.2):
    """Short inline animation shown before a blocking operation."""
    chars = ["🌑", "🌒", "🌓", "🌔", "🌕", "🌖", "🌗", "🌘"]
    end_time = time.time() + duration
    i = 0
    while time.time() < end_time:
        sys.stdout.write(f"\r  {chars[i % len(chars)]}  {DIM}{CYAN}{label}...{RESET}  ")
        sys.stdout.flush()
        time.sleep(0.1)
        i += 1
    sys.stdout.write("\r" + " " * (len(label) + 20) + "\r")
    sys.stdout.flush()


# ── Result table ──────────────────────────────────────────────────────────────

def print_result(data: list, total_rows: int):
    if not data:
        print(f"\n  {BRIGHT_YELLOW}🪐  No data returned from the galaxy.{RESET}\n")
        return

    # Animate "landing" the results
    _animate_data_landing(total_rows)

    columns    = list(data[0].keys())
    col_widths = {col: len(col) for col in columns}
    for row in data:
        for col in columns:
            val = str(row.get(col, ""))
            col_widths[col] = max(col_widths[col], min(len(val), 30))

    total_width = sum(col_widths.values()) + len(columns) * 3 + 2

    # Header
    header_line = "  " + " │ ".join(
        f"{BRIGHT_YELLOW}{col.ljust(col_widths[col])}{RESET}" for col in columns
    )
    separator = f"  {DIM}{'─' * total_width}{RESET}"

    print(f"\n{BRIGHT_GREEN}{BOLD}  🛬  Transmission received:{RESET} "
          f"{DIM}{total_rows:,} records · showing {min(len(data), 20):,}{RESET}")
    print(separator)
    print(header_line)
    print(separator)

    # Rows — stream them in with a tiny delay for effect
    for i, row in enumerate(data[:20]):
        row_str = "  " + " │ ".join(
            str(row.get(col, ""))[:30].ljust(col_widths[col])
            for col in columns
        )
        print(row_str)
        if i < 5:
            time.sleep(0.03)   # brief stagger on first 5 rows

    if len(data) > 20:
        print(f"  {DIM}✦  ... and {len(data) - 20:,} more records in the hold{RESET}")

    print(separator)
    print()


def _animate_data_landing(row_count: int):
    """Short rocket-landing animation before printing results."""
    frames = [
        f"  {BRIGHT_CYAN}         🚀{RESET}  {DIM}incoming transmission...{RESET}",
        f"  {BRIGHT_CYAN}       🚀  {RESET}  {DIM}incoming transmission...{RESET}",
        f"  {BRIGHT_CYAN}     🚀    {RESET}  {DIM}decoding {row_count:,} records...{RESET}",
        f"  {BRIGHT_CYAN}   🚀      {RESET}  {DIM}decoding {row_count:,} records...{RESET}",
        f"  {BRIGHT_GREEN}  🛬        {RESET}  {BRIGHT_GREEN}landing complete!{RESET}       ",
    ]
    for frame in frames:
        sys.stdout.write(f"\r{frame}")
        sys.stdout.flush()
        time.sleep(0.12)
    sys.stdout.write("\r" + " " * 55 + "\r")
    sys.stdout.flush()


# ── Cost badge ────────────────────────────────────────────────────────────────

def print_cost_badge(bytes_estimate: str):
    """Prints a colored cost badge based on the estimated scan size."""
    label = bytes_estimate.upper()
    if "GB" in label:
        val = float(label.replace("GB", "").strip())
        if val > 2:
            color, icon = RED,          "⚠️ "
        elif val > 0.5:
            color, icon = BRIGHT_YELLOW, "⚡"
        else:
            color, icon = BRIGHT_GREEN,  "✅"
    else:
        color, icon = BRIGHT_GREEN, "✅"

    print(f"  {icon}  {DIM}Estimated scan:{RESET} {color}{BOLD}{bytes_estimate}{RESET}")


# ── Error display ─────────────────────────────────────────────────────────────

def print_error(message: str):
    border = f"{RED}{'━' * 55}{RESET}"
    print(f"\n  {border}")
    print(f"  {RED}{BOLD}💥  Houston, we have a problem:{RESET}")
    print(f"  {RED}{message}{RESET}")
    print(f"  {border}\n")


# ── Success flash ─────────────────────────────────────────────────────────────

def print_success(message: str):
    print(f"  {BRIGHT_GREEN}✦  {message}{RESET}")


# ── Cache hit ─────────────────────────────────────────────────────────────────

def print_cache_hit():
    print(f"  {BRIGHT_CYAN}💾  Warp speed! Loaded from cache — zero BigQuery cost.{RESET}")


# ── Farewell ──────────────────────────────────────────────────────────────────

def print_goodbye():
    msgs = [
        "🚀  Safe travels through the data galaxy, Datanaut.",
        "🌌  Until next mission. Ad astra.",
        "🛸  Signing off from BigQuery orbit. Fly safe.",
        "⭐  The data will always be with you.",
    ]
    print(f"\n  {BRIGHT_CYAN}{random.choice(msgs)}{RESET}\n")