"""Desktop and log notifications for Brynq runtime events."""

import json
import logging
from datetime import datetime, timezone
from pathlib import Path

logger = logging.getLogger(__name__)


class NotificationPrefs:
    """Manage notification enabled/disabled preference."""

    _config_path = Path.home() / ".brynq" / "config.json"

    @classmethod
    def _read_config(cls) -> dict:
        if cls._config_path.exists():
            with open(cls._config_path, "r", encoding="utf-8") as f:
                return json.loads(f.read())
        return {}

    @classmethod
    def _write_config(cls, config: dict) -> None:
        cls._config_path.parent.mkdir(parents=True, exist_ok=True)
        with open(cls._config_path, "w", encoding="utf-8") as f:
            f.write(json.dumps(config, indent=2))

    @classmethod
    def enable(cls) -> None:
        config = cls._read_config()
        config["notifications_enabled"] = True
        cls._write_config(config)

    @classmethod
    def disable(cls) -> None:
        config = cls._read_config()
        config["notifications_enabled"] = False
        cls._write_config(config)

    @classmethod
    def is_enabled(cls) -> bool:
        config = cls._read_config()
        return config.get("notifications_enabled", True)


def notify(title: str, message: str) -> None:
    """Send a notification by logging it and appending to the notification log.

    Writes a JSON-lines entry to ~/.brynq/notifications.jsonl so that
    the runtime or UI can surface recent notifications.

    Args:
        title: Short notification title.
        message: Notification body text.
    """
    logger.info("%s: %s", title, message)
    log_dir = Path.home() / ".brynq"
    log_dir.mkdir(parents=True, exist_ok=True)
    entry = {
        "title": title,
        "message": message,
        "timestamp": datetime.now(timezone.utc).isoformat(),
    }
    log_file = log_dir / "notifications.jsonl"
    with open(log_file, "a", encoding="utf-8") as f:
        f.write(json.dumps(entry) + "\n")


def notify_chain_complete(
    chain_id: str,
    strategy: str,
    models: list[str],
    latency_ms: int,
) -> None:
    """Notify that a chain execution has completed.

    Args:
        chain_id: Unique identifier for the chain run.
        strategy: Chain strategy used (e.g. Sequential, FanOut, Debate).
        models: List of model names involved in the chain.
        latency_ms: Total execution latency in milliseconds.
    """
    message = (
        f"Chain {chain_id} finished. "
        f"Strategy: {strategy}, "
        f"Models: {len(models)}, "
        f"Latency: {latency_ms}ms"
    )
    notify("Brynq Chain Complete", message)


def notify_schedule_trigger(schedule_name: str, chain_template: str) -> None:
    """Notify that a scheduled chain has been triggered.

    Args:
        schedule_name: Name of the schedule that fired.
        chain_template: Chain template being executed.
    """
    body = f"Schedule '{schedule_name}' triggered chain template: {chain_template}"
    notify("Brynq Schedule Running", body)


def notify_batch_complete(
    job_id: str,
    total: int,
    succeeded: int,
    failed: int,
    duration_seconds: float,
) -> None:
    """Notify that a batch job has completed.

    Args:
        job_id: Unique identifier for the batch job.
        total: Total number of items in the batch.
        succeeded: Number of items that succeeded.
        failed: Number of items that failed.
        duration_seconds: Total batch duration in seconds.
    """
    message = (
        f"Batch {job_id}: {succeeded}/{total} succeeded, "
        f"{failed} failed in {duration_seconds:.1f}s"
    )
    notify("Brynq Batch Complete", message)


def notify_error(source: str, error_message: str) -> None:
    """Notify that an error occurred.

    Args:
        source: Component or module where the error originated.
        error_message: Description of the error.
    """
    body = f"[{source}] {error_message}"
    notify("Brynq Error", body)
