"""Sample Python, for checking syntax highlighting on a second language.

MDSyntax recognises roughly 190 languages and config formats. This file and
05-code.ts are highlighted by the same engine with different grammars, so
comparing them is a fair check that the language detection works off the
extension rather than guessing.
"""

from __future__ import annotations

import json
import math
from dataclasses import dataclass, field
from typing import Iterable, Iterator


@dataclass(frozen=True, slots=True)
class Reading:
    """One sensor reading."""

    label: str
    value: float
    unit: str = "C"
    tags: tuple[str, ...] = field(default_factory=tuple)

    def __str__(self) -> str:
        return f"{self.label}: {self.value:.1f}°{self.unit}"


def mean(values: Iterable[float]) -> float | None:
    """Arithmetic mean, or None for an empty sequence."""
    total, count = 0.0, 0
    for value in values:
        total += value
        count += 1
    return total / count if count else None


def stdev(values: Iterable[float]) -> float | None:
    sample = list(values)
    average = mean(sample)
    if average is None or len(sample) < 2:
        return None
    variance = sum((v - average) ** 2 for v in sample) / (len(sample) - 1)
    return math.sqrt(variance)


def outliers(readings: list[Reading], sigma: float = 2.0) -> Iterator[Reading]:
    """Yield readings further than `sigma` standard deviations from the mean."""
    values = [r.value for r in readings]
    average, spread = mean(values), stdev(values)
    if average is None or spread in (None, 0.0):
        return
    assert spread is not None
    for reading in readings:
        if abs(reading.value - average) > sigma * spread:
            yield reading


READINGS = [
    Reading("kitchen", 21.4, tags=("indoor",)),
    Reading("hallway", 20.9, tags=("indoor",)),
    Reading("attic", 38.2, tags=("indoor", "unheated")),
    Reading("garden", 14.1, tags=("outdoor",)),
]


def main() -> None:
    for reading in READINGS:
        print(reading)

    flagged = list(outliers(READINGS))
    print(f"\n{len(flagged)} outlier(s):")
    for reading in flagged:
        print(f"  - {reading} {list(reading.tags)}")

    print(json.dumps({r.label: r.value for r in READINGS}, indent=2, sort_keys=True))


if __name__ == "__main__":
    main()
