import datetime
import time
from itertools import cycle
from threading import Thread
from colorama import Fore


class Loader:
    """
    Animated terminal spinner / loading indicator.

    Usage:
        # As context manager (recommended)
        with Loader(desc="Fetching data", end="Done!"):
            time.sleep(3)

        # Manual control
        loader = Loader(desc="Processing")
        loader.start()
        time.sleep(3)
        loader.stop()
    """

    PINK           = "\033[38;5;176m"
    MAGENTA        = "\033[38;5;97m"
    BRIGHT_MAGENTA = "\033[38;2;157;38;255m"
    GREEN          = "\033[38;5;40m"

    FRAMES = ["⢿", "⣻", "⣽", "⣾", "⣷", "⣯", "⣟", "⡿"]

    def __init__(
        self,
        prefix: str = "karenhoyoshi.asia",
        desc: str = "Loading...",
        end: str = "\r",
        timeout: float = 0.1,
    ):
        self.prefix = prefix
        self.desc = desc
        self.end = end
        self.timeout = timeout
        self.done = False
        self._thread = Thread(target=self._animate, daemon=True)

    # ── Context manager ───────────────────────────────────────────────────────

    def __enter__(self):
        self.start()
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.stop()

    # ── Control ───────────────────────────────────────────────────────────────

    def start(self):
        self.done = False
        self._thread = Thread(target=self._animate, daemon=True)
        self._thread.start()
        return self

    def stop(self):
        self.done = True
        self._thread.join()
        if self.end != "\r":
            current_time = datetime.datetime.now().strftime("%H:%M:%S")
            print(
                f"\n{self.PINK}[{self.MAGENTA}{self.prefix}{self.PINK}] "
                f"[{self.BRIGHT_MAGENTA}{current_time}{self.PINK}] "
                f"{self.GREEN} {self.end} {Fore.RESET}",
                flush=True,
            )
        else:
            print("\r" + " " * 80 + "\r", end="", flush=True)

    # ── Internal ──────────────────────────────────────────────────────────────

    def _animate(self):
        for frame in cycle(self.FRAMES):
            if self.done:
                break
            current_time = datetime.datetime.now().strftime("%H:%M:%S")
            print(
                f"\r{self.PINK}[{self.MAGENTA}{self.prefix}{self.PINK}] "
                f"[{self.BRIGHT_MAGENTA}{current_time}{self.PINK}] "
                f"[{self.GREEN}{self.desc}{self.PINK}]{Fore.RESET} {frame}",
                flush=True,
                end="",
            )
            time.sleep(self.timeout)
