#!/usr/bin/python3
# cal-notif: calendar notifications with local spoken announcements.
# Copyright (C) 2026 Danilo M. <danix@danix.xyz>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
"""Usage: cal-notif daemon | pick | say TEXT

daemon  watch the calendars and notify (popup + voice) at each alarm
pick    rofi picker to set custom alarm offsets for one event
say     speak TEXT with the configured voice
"""

import json
import os
import re
import shutil
import subprocess
import sys
import time
import tomllib
from collections import namedtuple
from datetime import datetime, time as dtime, timedelta, timezone
from pathlib import Path

from dateutil.rrule import rrulestr
from icalendar import Calendar, vRecur

# ---- durations ----

DUR = re.compile(r"(?:(\d+)d)?(?:(\d+)h)?(?:(\d+)m)?")


def parse_duration(s):
    m = DUR.fullmatch(s.replace(" ", ""))
    if not s.strip() or not m:
        raise ValueError(f"bad duration {s!r}, want e.g. '1d 2h 15m'")
    d, h, mi = (int(x or 0) for x in m.groups())
    return timedelta(days=d, hours=h, minutes=mi)


def fmt_duration(td):
    m = round(td.total_seconds() / 60)
    d, m = divmod(m, 1440)
    h, m = divmod(m, 60)
    return " ".join(f"{n}{u}" for n, u in ((d, "d"), (h, "h"), (m, "m")) if n) or "0m"


UNITS = ["", "uno", "due", "tre", "quattro", "cinque", "sei", "sette", "otto", "nove",
         "dieci", "undici", "dodici", "tredici", "quattordici", "quindici", "sedici",
         "diciassette", "diciotto", "diciannove"]
TENS = ["", "", "venti", "trenta", "quaranta", "cinquanta", "sessanta", "settanta",
        "ottanta", "novanta"]


def number_it(n):
    # 1..99; ventuno, ventotto: the tens drop their vowel before uno/otto.
    if n < 20:
        return UNITS[n]
    t, u = divmod(n, 10)
    return (TENS[t][:-1] if u in (1, 8) else TENS[t]) + UNITS[u]


def spoken_it(td):
    m = round(td.total_seconds() / 60)
    d, m = divmod(m, 1440)
    h, m = divmod(m, 60)
    parts = []
    for n, one, many in ((d, "un giorno", "giorni"), (h, "un'ora", "ore"), (m, "un minuto", "minuti")):
        if n == 1:
            parts.append(one)
        elif n:
            # ponytail: number_it covers 1-99; bigger counts are read as digits.
            parts.append(f"{number_it(n) if n < 100 else n} {many}")
    if not parts:
        return ""
    return parts[0] if len(parts) == 1 else ", ".join(parts[:-1]) + " e " + parts[-1]

# ---- config ----

# ---- calendars ----

# ---- alarms ----

# ---- voice ----

# ---- daemon ----

# ---- picker ----


def main():
    sys.exit(__doc__)


if __name__ == "__main__":
    main()
