# utils/notify.py
from typing import Iterable, Optional
from models import db, Employee  # Employee needed for fan-out
from models import Notification


def _safe_text(value: Optional[str]) -> Optional[str]:
    """
    Ensure text is ASCII-only to avoid MySQL 'Incorrect string value' errors
    when the notifications table/columns are not utf8mb4.

    - None stays None
    - Non-ASCII characters are stripped (e.g. arrows, emojis)
    """
    if value is None:
        return None
    # encode to ASCII, dropping characters that can't be encoded
    return value.encode("ascii", "ignore").decode("ascii")


def notify_employee(
    employee_id: Optional[int],  # None => broadcast row
    title: str,
    message: str = "",
    link: Optional[str] = None,
    commit: bool = True,
):
    title_safe = _safe_text(title)
    message_safe = _safe_text(message or "")
    link_safe = _safe_text(link) if link is not None else None

    n = Notification(
        employee_id=employee_id,
        title=title_safe,
        message=message_safe,
        link=link_safe,
    )
    db.session.add(n)
    if commit:
        db.session.commit()
    return n


def notify_many(
    employee_ids: Iterable[int],
    title: str,
    message: str = "",
    link: Optional[str] = None,
):
    ids = list({i for i in employee_ids if i})
    if not ids:
        return 0

    title_safe = _safe_text(title)
    message_safe = _safe_text(message or "")
    link_safe = _safe_text(link) if link is not None else None

    objs = [
        Notification(
            employee_id=eid,
            title=title_safe,
            message=message_safe,
            link=link_safe,
        )
        for eid in ids
    ]
    db.session.bulk_save_objects(objs)
    db.session.commit()
    return len(objs)


def notify_broadcast(
    title: str,
    message: str = "",
    link: Optional[str] = None,
    fanout: bool = True,
):
    """
    Broadcast to everyone.
    - fanout=True  -> create one row per active employee (best for per-user unread/read)
    - fanout=False -> create a single NULL (broadcast) row
    """
    if fanout:
        ids = [e.id for e in Employee.query.filter(Employee.status == "active").all()]
        return notify_many(ids, title, message, link)

    # pure broadcast: single row with employee_id = NULL
    notify_employee(None, title, message, link, commit=True)
    return 1