"""Jinja2 template filters for the web UI."""

from __future__ import annotations

from datetime import datetime, timezone
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from flask import Flask


def timeago(dt: datetime | str | None) -> str:
    """Convert a datetime to a human-readable 'time ago' string.

    Examples:
        - "just now"
        - "2 minutes ago"
        - "3 hours ago"
        - "yesterday"
        - "5 days ago"
        - "2 weeks ago"
        - "3 months ago"
        - "1 year ago"
    """
    if dt is None:
        return "unknown"

    if isinstance(dt, str):
        try:
            dt = datetime.fromisoformat(dt.replace("Z", "+00:00"))
        except ValueError:
            return dt

    now = datetime.now(timezone.utc)
    if dt.tzinfo is None:
        dt = dt.replace(tzinfo=timezone.utc)

    diff = now - dt
    seconds = diff.total_seconds()

    if seconds < 60:
        return "just now"
    elif seconds < 3600:
        minutes = int(seconds / 60)
        return f"{minutes} minute{'s' if minutes != 1 else ''} ago"
    elif seconds < 86400:
        hours = int(seconds / 3600)
        return f"{hours} hour{'s' if hours != 1 else ''} ago"
    elif seconds < 172800:
        return "yesterday"
    elif seconds < 604800:
        days = int(seconds / 86400)
        return f"{days} days ago"
    elif seconds < 2592000:
        weeks = int(seconds / 604800)
        return f"{weeks} week{'s' if weeks != 1 else ''} ago"
    elif seconds < 31536000:
        months = int(seconds / 2592000)
        return f"{months} month{'s' if months != 1 else ''} ago"
    else:
        years = int(seconds / 31536000)
        return f"{years} year{'s' if years != 1 else ''} ago"


def format_number(num: int | float | None) -> str:
    """Format a number with K/M suffixes for readability.

    Examples:
        - 123 → "123"
        - 1234 → "1.2K"
        - 12345 → "12.3K"
        - 1234567 → "1.2M"
    """
    if num is None:
        return "0"

    num = float(num)

    if num >= 1_000_000:
        formatted = num / 1_000_000
        result = f"{formatted:.1f}".rstrip("0").rstrip(".")
        return f"{result}M"
    elif num >= 1_000:
        formatted = num / 1_000
        result = f"{formatted:.1f}".rstrip("0").rstrip(".")
        return f"{result}K"
    else:
        return str(int(num))


def date_format(dt: datetime | str | None, fmt: str = "%b %d, %Y") -> str:
    """Format a datetime as a readable date string.

    Args:
        dt: The datetime to format
        fmt: strftime format string (default: "Jan 01, 2025")

    Examples:
        - "Jan 15, 2025"
        - "Dec 31, 2024"
    """
    if dt is None:
        return ""

    if isinstance(dt, str):
        try:
            dt = datetime.fromisoformat(dt.replace("Z", "+00:00"))
        except ValueError:
            return dt

    return dt.strftime(fmt)


def truncate_words(text: str | None, length: int = 20, suffix: str = "...") -> str:
    """Truncate text to a maximum number of words.

    Args:
        text: The text to truncate
        length: Maximum number of words
        suffix: String to append if truncated
    """
    if not text:
        return ""

    words = text.split()
    if len(words) <= length:
        return text

    return " ".join(words[:length]) + suffix


def register_filters(app: Flask) -> None:
    """Register all custom filters with a Flask app."""
    app.jinja_env.filters["timeago"] = timeago
    app.jinja_env.filters["format_number"] = format_number
    app.jinja_env.filters["date_format"] = date_format
    app.jinja_env.filters["truncate_words"] = truncate_words

    # Global functions
    app.jinja_env.globals["now"] = datetime.utcnow
