# Familiar - Self-Hosted AI Companion Platform
# Copyright (c) 2026 George Scott Foley
# ORCID: 0009-0006-4957-0540
# Email: Georgescottfoley@proton.me
# Licensed under the MIT License - see LICENSE file for details

"""
Creature Display

Renders the creature in a retro box frame with status bar.
Uses Unicode box-drawing characters and ANSI colors.
"""

import time

from .palette import build_color_map
from .renderer import render_frame
from .species import EVOLUTION_FLAVOR
from .sprites import get_sprite_frames
from .state import ActivityState, CreatureState

# Box-drawing in dim cyan (matches onboard.py style)
DIM_CYAN = "\033[2m\033[96m"
BOLD = "\033[1m"
RESET = "\033[0m"
DIM = "\033[2m"


class CreatureDisplay:
    """Renders the creature in a retro terminal box."""

    def __init__(self, state: CreatureState):
        self.state = state
        self._frame_index = 0
        self._colors = build_color_map(state.color_body, state.color_eyes, state.color_accent)
        self._box_width = 28  # inner width

    def show(
        self,
        activity: ActivityState = ActivityState.IDLE,
        status_text: str = "",
    ) -> None:
        """Print the creature in its box frame."""
        frames = get_sprite_frames(
            self.state.species,
            self.state.evolution_stage,
            activity.value,
        )
        frame = frames[self._frame_index % len(frames)]
        self._frame_index += 1

        rendered = render_frame(frame, self._colors)
        self._print_box(rendered, activity, status_text)

    def show_evolution(self, old_stage: str, new_stage: str) -> None:
        """Display the evolution animation."""
        species = self.state.species

        # Flash effect
        print()
        print(f"  {BOLD}Something is happening...{RESET}")
        time.sleep(0.8)

        # Show sparkle frames
        for i in range(3):
            sparkles = "  " + " ".join(["*" if (i + j) % 2 == 0 else "." for j in range(12)])
            print(f"\r{sparkles}", end="", flush=True)
            time.sleep(0.3)
        print()

        # Show new form
        flavor = EVOLUTION_FLAVOR.get(species, {}).get(new_stage, "Your familiar evolved!")
        print(f"\n  {BOLD}{self.state.name} evolved to {new_stage}!{RESET}")
        print(f"  {DIM}{flavor}{RESET}")
        print()

        # Update colors and show new form
        self._colors = build_color_map(
            self.state.color_body,
            self.state.color_eyes,
            self.state.color_accent,
        )
        self._frame_index = 0
        self.show(ActivityState.IDLE)

    def clear(self) -> None:
        """Print blank lines to visually separate from previous display."""
        print()

    def _print_box(
        self,
        rendered_lines: list[str],
        activity: ActivityState,
        status_text: str,
    ) -> None:
        """Print the creature inside a retro box frame."""
        w = self._box_width
        bc = DIM_CYAN  # border color
        h_line = "\u2500" * w

        # Top border
        print(f"  {bc}\u250c{h_line}\u2510{RESET}")

        # Empty row above creature
        print(f"  {bc}\u2502{RESET}{' ' * w}{bc}\u2502{RESET}")

        # Creature rows, centered
        for line in rendered_lines:
            # Strip ANSI to measure visible width
            visible = _strip_ansi(line)
            pad_total = w - len(visible)
            pad_left = pad_total // 2
            pad_right = pad_total - pad_left
            if pad_total < 0:
                # Sprite wider than box — expand box
                pad_left = 1
                pad_right = 1
            print(f"  {bc}\u2502{RESET}{' ' * pad_left}{line}{' ' * pad_right}{bc}\u2502{RESET}")

        # Empty row below creature
        print(f"  {bc}\u2502{RESET}{' ' * w}{bc}\u2502{RESET}")

        # Status bar
        name_str = self.state.name
        if status_text:
            status_str = status_text
        else:
            status_str = activity.value

        # Truncate if needed
        max_name = w - len(status_str) - 2
        if len(name_str) > max_name:
            name_str = name_str[: max_name - 1] + "\u2026"

        padding = w - len(name_str) - len(status_str)
        if padding < 1:
            padding = 1
        status_line = f" {BOLD}{name_str}{RESET}{' ' * (padding - 1)}{DIM}{status_str} {RESET}"
        print(f"  {bc}\u2502{RESET}{status_line}{bc}\u2502{RESET}")

        # Bottom border
        print(f"  {bc}\u2514{h_line}\u2518{RESET}")


def _strip_ansi(text: str) -> str:
    """Remove ANSI escape sequences to measure visible string width."""
    import re

    return re.sub(r"\033\[[0-9;]*m", "", text)
