"""
Birthday animation engine - smooth terminal animations with cake, confetti, balloons.
Cross-platform: Windows, macOS, Linux.
"""

import os
import sys
import time
import random
import shutil
import threading

# ──────────────────────────────────────────────────────────────
# ANSI color helpers (works on Win10+, macOS, Linux)
# ──────────────────────────────────────────────────────────────

def _enable_ansi_windows():
    """Enable ANSI escape codes on Windows 10+."""
    if sys.platform == "win32":
        try:
            import ctypes
            kernel32 = ctypes.windll.kernel32
            # Enable VIRTUAL_TERMINAL_PROCESSING
            kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
        except Exception:
            pass

_enable_ansi_windows()

# Color codes
RESET   = "\033[0m"
BOLD    = "\033[1m"
BLINK   = "\033[5m"

# Foreground
RED     = "\033[91m"
GREEN   = "\033[92m"
YELLOW  = "\033[93m"
BLUE    = "\033[94m"
MAGENTA = "\033[95m"
CYAN    = "\033[96m"
WHITE   = "\033[97m"
ORANGE  = "\033[38;5;208m"
PINK    = "\033[38;5;213m"
GOLD    = "\033[38;5;220m"
LIGHT_BLUE = "\033[38;5;117m"

COLORS = [RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, ORANGE, PINK, GOLD, LIGHT_BLUE]

def random_color():
    return random.choice(COLORS)

def colored(text, color):
    return f"{color}{text}{RESET}"

def bold(text):
    return f"{BOLD}{text}{RESET}"

def clear_screen():
    os.system("cls" if os.name == "nt" else "clear")

def get_terminal_size():
    try:
        cols, rows = shutil.get_terminal_size((80, 24))
    except Exception:
        cols, rows = 80, 24
    return cols, rows

def hide_cursor():
    sys.stdout.write("\033[?25l")
    sys.stdout.flush()

def show_cursor():
    sys.stdout.write("\033[?25h")
    sys.stdout.flush()

def move_cursor(row, col):
    sys.stdout.write(f"\033[{row};{col}H")
    sys.stdout.flush()


# ──────────────────────────────────────────────────────────────
# ASCII art assets
# ──────────────────────────────────────────────────────────────

CAKE = r"""
                         iiiiiiiiii
                    |||||||||||||||||||
                    |||||||||||||||||||
                         |  .  |
                         |     |
               __________|___ |__________
              |  . ' .    |   |   . '  . |
              | '  .'  '  | ~ |  '  '.   |
              |  '  . '   |___|  '  .  '  |
              |.  '. '  __________  ' . ' |
              | .'  '  |  . '  . |  .'  '.|
              |' .  '  | '  .'  '| '  .  '|
              | '  .'  |  '  . ' |  '. '  |
              |.  '. ' |.  '. '  | '  .  '|
              |_________|________|_________|
         _____|_____|_____|_____|_____|_____|_____
        |  .  ' .  |  .  '  .  |  .  '  .  | . ' |
        |  . ' . ' | ' .  ' .  |  ' .  ' . | ' . |
        |__________|___________|___________|______|
"""

CAKE_SMALL = r"""
            *  *  *  *  *
           | || || || || |
           | || || || || |
        _____|_____|_____
       |  ~  Happy B'day |
       |   🎂  JYOTI  🎂  |
       |_________________|
       |  *  *  *  *  *  |
       |  *  *  *  *  *  |
       |_________________|
"""

BALLOON_CHARS = ["🎈", "🎈", "🎈", "🎈"]
CONFETTI_CHARS = ["✦", "✧", "★", "☆", "◆", "◇", "●", "○", "♦", "♥", "♠", "♣", "✿", "❀", "❁", "✾", "⁂", "※"]
PARTY_CHARS = ["🎉", "🎊", "🎁", "🎀", "🎵", "🎶", "💃", "🕺", "✨", "💖", "🥳", "🍰"]

# ──────────────────────────────────────────────────────────────
# Animation functions
# ──────────────────────────────────────────────────────────────

def print_centered(text, color=WHITE):
    cols, _ = get_terminal_size()
    for line in text.split("\n"):
        padding = max(0, (cols - len(line)) // 2)
        sys.stdout.write(" " * padding + colored(line, color) + "\n")
    sys.stdout.flush()


def animate_typing(text, color=WHITE, delay=0.04):
    """Type text character by character."""
    for ch in text:
        sys.stdout.write(colored(ch, color))
        sys.stdout.flush()
        time.sleep(delay)


def sparkle_border(duration=2.0):
    """Animate a sparkle border around the terminal."""
    cols, rows = get_terminal_size()
    start = time.time()
    while time.time() - start < duration:
        # Top border
        move_cursor(1, 1)
        line = "".join(colored(random.choice(CONFETTI_CHARS), random_color()) for _ in range(min(cols // 2, 60)))
        sys.stdout.write(line)
        # Bottom border
        move_cursor(rows, 1)
        line = "".join(colored(random.choice(CONFETTI_CHARS), random_color()) for _ in range(min(cols // 2, 60)))
        sys.stdout.write(line)
        sys.stdout.flush()
        time.sleep(0.1)


def confetti_rain(duration=3.0):
    """Rain confetti down the terminal."""
    cols, rows = get_terminal_size()
    particles = []
    start = time.time()

    # Initialize particles
    for _ in range(50):
        particles.append({
            "x": random.randint(1, cols - 1),
            "y": random.randint(1, 3),
            "char": random.choice(CONFETTI_CHARS),
            "color": random_color(),
            "speed": random.uniform(0.3, 1.0),
        })

    while time.time() - start < duration:
        for p in particles:
            # Clear old position
            move_cursor(int(p["y"]), p["x"])
            sys.stdout.write(" ")

            # Update position
            p["y"] += p["speed"]
            if p["y"] >= rows - 1:
                p["y"] = 1
                p["x"] = random.randint(1, cols - 1)
                p["char"] = random.choice(CONFETTI_CHARS)
                p["color"] = random_color()

            # Draw new position
            move_cursor(int(p["y"]), p["x"])
            sys.stdout.write(colored(p["char"], p["color"]))

        sys.stdout.flush()
        time.sleep(0.05)


def balloon_rise(duration=3.0):
    """Animate balloons rising up the terminal."""
    cols, rows = get_terminal_size()
    balloons = []

    for _ in range(15):
        balloons.append({
            "x": random.randint(2, cols - 3),
            "y": rows - 1,
            "color": random_color(),
            "speed": random.uniform(0.3, 0.8),
            "char": random.choice(["O", "o", "0", "@"]),
        })

    start = time.time()
    while time.time() - start < duration:
        for b in balloons:
            # Clear old
            move_cursor(int(b["y"]), b["x"])
            sys.stdout.write("  ")
            if int(b["y"]) + 1 < rows:
                move_cursor(int(b["y"]) + 1, b["x"])
                sys.stdout.write("  ")

            # Move up
            b["y"] -= b["speed"]
            b["x"] += random.choice([-1, 0, 0, 1])  # slight sway
            b["x"] = max(1, min(cols - 2, b["x"]))

            if b["y"] <= 1:
                b["y"] = rows - 1
                b["x"] = random.randint(2, cols - 3)

            # Draw balloon
            row = int(b["y"])
            move_cursor(row, b["x"])
            sys.stdout.write(colored(b["char"], b["color"]))
            if row + 1 < rows:
                move_cursor(row + 1, b["x"])
                sys.stdout.write(colored("|", b["color"]))

        sys.stdout.flush()
        time.sleep(0.07)


def fireworks(duration=3.0):
    """Simple firework bursts at random positions."""
    cols, rows = get_terminal_size()
    start = time.time()
    burst_patterns = [
        [(-1, 0), (1, 0), (0, -1), (0, 1), (-1, -1), (-1, 1), (1, -1), (1, 1)],
        [(-2, 0), (2, 0), (0, -2), (0, 2), (-1, -1), (-1, 1), (1, -1), (1, 1),
         (-2, -1), (-2, 1), (2, -1), (2, 1)],
    ]

    while time.time() - start < duration:
        cx = random.randint(5, cols - 5)
        cy = random.randint(4, rows - 4)
        color = random_color()
        pattern = random.choice(burst_patterns)
        char = random.choice(["*", "+", "✦", "✧", "★", "●"])

        # Draw burst
        move_cursor(cy, cx)
        sys.stdout.write(colored("✸", color))
        for dy, dx in pattern:
            ny, nx = cy + dy, cx + dx
            if 1 <= ny <= rows and 1 <= nx <= cols:
                move_cursor(ny, nx)
                sys.stdout.write(colored(char, color))
        sys.stdout.flush()
        time.sleep(0.3)

        # Erase burst
        move_cursor(cy, cx)
        sys.stdout.write(" ")
        for dy, dx in pattern:
            ny, nx = cy + dy, cx + dx
            if 1 <= ny <= rows and 1 <= nx <= cols:
                move_cursor(ny, nx)
                sys.stdout.write(" ")
        sys.stdout.flush()
        time.sleep(0.1)


def rainbow_text(text, row=None):
    """Print text with rainbow colors, centered."""
    cols, _ = get_terminal_size()
    padding = max(0, (cols - len(text)) // 2)
    if row:
        move_cursor(row, 1)
    sys.stdout.write(" " * padding)
    for i, ch in enumerate(text):
        color = COLORS[i % len(COLORS)]
        sys.stdout.write(colored(ch, color))
    sys.stdout.write("\n")
    sys.stdout.flush()


def pulsing_text(text, cycles=3, delay=0.15):
    """Pulse text by toggling bold on/off."""
    cols, _ = get_terminal_size()
    padding = " " * max(0, (cols - len(text)) // 2)
    for _ in range(cycles):
        sys.stdout.write(f"\r{padding}{BOLD}{random_color()}{text}{RESET}")
        sys.stdout.flush()
        time.sleep(delay)
        sys.stdout.write(f"\r{padding}{random_color()}{text}{RESET}")
        sys.stdout.flush()
        time.sleep(delay)
    sys.stdout.write("\n")


def wave_text(text, cycles=2):
    """Animate text in a wave pattern."""
    cols, _ = get_terminal_size()
    padding = max(0, (cols - len(text) - 4) // 2)
    for cycle in range(cycles):
        for offset in range(len(text)):
            sys.stdout.write("\r" + " " * padding)
            for i, ch in enumerate(text):
                if i == offset or i == offset - 1 or i == offset + 1:
                    sys.stdout.write(colored(ch.upper(), YELLOW) if i == offset else colored(ch, GOLD))
                else:
                    sys.stdout.write(colored(ch, CYAN))
            sys.stdout.flush()
            time.sleep(0.03)
    sys.stdout.write("\n")


# ──────────────────────────────────────────────────────────────
# Main celebration sequence
# ──────────────────────────────────────────────────────────────

HAPPY_BIRTHDAY_BANNER = r"""
 ██╗  ██╗ █████╗ ██████╗ ██████╗ ██╗   ██╗
 ██║  ██║██╔══██╗██╔══██╗██╔══██╗╚██╗ ██╔╝
 ███████║███████║██████╔╝██████╔╝ ╚████╔╝
 ██╔══██║██╔══██║██╔═══╝ ██╔═══╝   ╚██╔╝
 ██║  ██║██║  ██║██║     ██║        ██║
 ╚═╝  ╚═╝╚═╝  ╚═╝╚═╝     ╚═╝        ╚═╝

 ██████╗ ██╗██████╗ ████████╗██╗  ██╗██████╗  █████╗ ██╗   ██╗
 ██╔══██╗██║██╔══██╗╚══██╔══╝██║  ██║██╔══██╗██╔══██╗╚██╗ ██╔╝
 ██████╔╝██║██████╔╝   ██║   ███████║██║  ██║███████║ ╚████╔╝
 ██╔══██╗██║██╔══██╗   ██║   ██╔══██║██║  ██║██╔══██║  ╚██╔╝
 ██████╔╝██║██║  ██║   ██║   ██║  ██║██████╔╝██║  ██║   ██║
 ╚═════╝ ╚═╝╚═╝  ╚═╝   ╚═╝   ╚═╝  ╚═╝╚═════╝ ╚═╝  ╚═╝   ╚═╝
"""

JYOTI_BANNER = r"""
          ██╗██╗   ██╗ ██████╗ ████████╗██╗
          ██║╚██╗ ██╔╝██╔═══██╗╚══██╔══╝██║
          ██║ ╚████╔╝ ██║   ██║   ██║   ██║
     ██   ██║  ╚██╔╝  ██║   ██║   ██║   ██║
     ╚█████╔╝   ██║   ╚██████╔╝   ██║   ██║
      ╚════╝    ╚═╝    ╚═════╝    ╚═╝   ╚═╝
"""


NAMES_MESSAGE = """
╔══════════════════════════════════════════════════════════════╗
║                                                              ║
║     With lots of love from:                                  ║
║                                                              ║
║       💖  Sindhu      💖  Akaash      💖  Neha               ║
║       💖  Rajat       💖  Ujjwal      💖  Leena              ║
║       💖  Anubha      💖  Partho      💖  Sumit              ║
║       💖  Rudraksh    💖  Kavita      💖  Muskan             ║
║       💖  Ishika                                             ║
║                                                              ║
║                  🌟 TEAM TONGADIVE 🌟                        ║
║                                                              ║
║          Take care - Love yourself Always 💕                 ║
║                                                              ║
╚══════════════════════════════════════════════════════════════╝
"""


def run_celebration():
    """Run the full birthday celebration animation."""
    hide_cursor()
    try:
        _run_celebration_inner()
    except KeyboardInterrupt:
        pass
    finally:
        show_cursor()
        print(RESET)


def _run_celebration_inner():
    cols, rows = get_terminal_size()

    # ── Phase 1: Dramatic entrance ──────────────────────────
    clear_screen()
    time.sleep(0.3)

    # Countdown
    countdown_chars = ["3", "2", "1"]
    for ch in countdown_chars:
        clear_screen()
        big = f"""
        {'=' * 20}
             {ch}
        {'=' * 20}
        """
        mid_row = rows // 2 - 2
        move_cursor(mid_row, 1)
        print_centered(f"{'=' * 20}", random_color())
        move_cursor(mid_row + 1, 1)
        rainbow_text(f"       {ch}       ")
        move_cursor(mid_row + 2, 1)
        print_centered(f"{'=' * 20}", random_color())
        time.sleep(0.6)

    # ── Phase 2: Confetti explosion ─────────────────────────
    clear_screen()
    confetti_rain(duration=2.5)

    # ── Phase 3: Big banner ─────────────────────────────────
    clear_screen()
    time.sleep(0.2)

    # Print HAPPY BIRTHDAY with rainbow colors line by line
    lines = HAPPY_BIRTHDAY_BANNER.strip().split("\n")
    for i, line in enumerate(lines):
        color = COLORS[i % len(COLORS)]
        print_centered(line, color)
        time.sleep(0.08)

    time.sleep(0.5)

    # Print JYOTI with pulsing effect
    jyoti_lines = JYOTI_BANNER.strip().split("\n")
    for i, line in enumerate(jyoti_lines):
        color = COLORS[(i + 3) % len(COLORS)]
        print_centered(line, color)
        time.sleep(0.08)

    time.sleep(1.0)

    # ── Phase 4: Cake ──────────────────────────────────────
    clear_screen()
    time.sleep(0.2)

    # Party emoji header
    party_line = " ".join(random.choice(PARTY_CHARS) for _ in range(min(cols // 3, 20)))
    print_centered(party_line, YELLOW)
    print()

    cake_lines = CAKE.strip().split("\n")
    cake_colors = [YELLOW, GOLD, ORANGE, RED, MAGENTA, PINK, CYAN]
    for i, line in enumerate(cake_lines):
        color = cake_colors[i % len(cake_colors)]
        print_centered(line, color)
        time.sleep(0.05)

    print()
    party_line2 = " ".join(random.choice(PARTY_CHARS) for _ in range(min(cols // 3, 20)))
    print_centered(party_line2, YELLOW)

    time.sleep(1.5)

    # ── Phase 5: Balloons ──────────────────────────────────
    clear_screen()

    # Draw a static "HAPPY BIRTHDAY JYOTI" in center while balloons rise
    mid = rows // 2
    move_cursor(mid, 1)
    rainbow_text("🎂  H A P P Y   B I R T H D A Y   J Y O T I  🎂")
    move_cursor(mid + 2, 1)
    rainbow_text("🎈 🎈 🎈 🎈 🎈 🎈 🎈 🎈 🎈 🎈 🎈 🎈 🎈 🎈 🎈")

    balloon_rise(duration=3.0)

    # ── Phase 6: Fireworks ─────────────────────────────────
    clear_screen()
    move_cursor(rows // 2, 1)
    rainbow_text("✨  C E L E B R A T I N G   J Y O T I  ✨")
    fireworks(duration=3.0)

    # ── Phase 7: Names & message ───────────────────────────
    clear_screen()
    time.sleep(0.3)

    # Sparkle border in a thread
    border_thread = threading.Thread(target=sparkle_border, args=(3.0,), daemon=True)
    border_thread.start()

    # Print the love message
    move_cursor(3, 1)
    msg_lines = NAMES_MESSAGE.strip().split("\n")
    for i, line in enumerate(msg_lines):
        color = COLORS[i % len(COLORS)]
        print_centered(line, color)
        time.sleep(0.1)

    border_thread.join()

    # ── Phase 8: Final wave text ───────────────────────────
    time.sleep(0.5)
    print()
    wave_text("🎂 HAPPY BIRTHDAY JYOTI! 🎂", cycles=3)
    print()
    pulsing_text("🌟 You are amazing! 🌟", cycles=4)
    print()
    pulsing_text("💖 Love from Team TongaDive 💖", cycles=4)
    print()

    # Final confetti
    print()
    for _ in range(3):
        line = " ".join(colored(random.choice(CONFETTI_CHARS), random_color()) for _ in range(min(cols // 3, 30)))
        cols_w, _ = get_terminal_size()
        padding = " " * max(0, (cols_w - min(cols // 3, 30) * 2) // 2)
        print(padding + line)
        time.sleep(0.1)

    print()
    print_centered("Press Enter to exit... 🎉", CYAN)

    # Keep screen alive until user presses enter
    try:
        input()
    except (EOFError, KeyboardInterrupt):
        pass
