#!/usr/bin/env python3
"""
Report calendar dates missing from MM-DD.mp3 files in the current directory.

Scans filenames matching MM-DD.mp3 (and MM-DD_2.mp3, etc. from collision
suffixes) and lists every valid month/day not represented, in chronological
order.

Usage:
    python missing_dates.py
    python missing_dates.py --year 2024
    python missing_dates.py --group-by-month
"""

from __future__ import annotations

import argparse
import calendar
import re
from datetime import date
from pathlib import Path

# MM-DD.mp3 or MM-DD_2.mp3, MM-DD_3.mp3, …
DATE_FILENAME_RE = re.compile(
    r"^(?P<month>\d{2})-(?P<day>\d{2})(?:_\d+)?\.mp3$",
    re.IGNORECASE,
)

MONTH_NAMES = [
    "", "January", "February", "March", "April", "May", "June",
    "July", "August", "September", "October", "November", "December",
]


def collect_present_dates(directory: Path) -> set[tuple[int, int]]:
    """Return (month, day) pairs found in MM-DD*.mp3 filenames."""
    present: set[tuple[int, int]] = set()

    for mp3 in directory.glob("*.mp3"):
        match = DATE_FILENAME_RE.match(mp3.name)
        if not match:
            continue
        month = int(match.group("month"))
        day = int(match.group("day"))
        if 1 <= month <= 12 and 1 <= day <= 31:
            present.add((month, day))

    return present


def all_calendar_dates(year: int) -> list[tuple[int, int]]:
    """Every valid (month, day) in *year*, Jan 1 through Dec 31."""
    dates: list[tuple[int, int]] = []
    for month in range(1, 13):
        _, days_in_month = calendar.monthrange(year, month)
        for day in range(1, days_in_month + 1):
            dates.append((month, day))
    return dates


def format_date(month: int, day: int) -> str:
    return f"{month:02d}-{day:02d}"


def main() -> None:
    parser = argparse.ArgumentParser(
        description="List calendar dates missing from MM-DD.mp3 files.",
    )
    parser.add_argument(
        "--year",
        type=int,
        default=date.today().year,
        help="Calendar year to evaluate (affects Feb 29). Default: current year.",
    )
    parser.add_argument(
        "--group-by-month",
        action="store_true",
        help="Print missing dates grouped under month headings.",
    )
    args = parser.parse_args()

    cwd = Path.cwd()
    present = collect_present_dates(cwd)
    all_dates = all_calendar_dates(args.year)
    missing = [(m, d) for m, d in all_dates if (m, d) not in present]

    total_days = len(all_dates)
    found = total_days - len(missing)

    print(f"Directory : {cwd}")
    print(f"Year      : {args.year} ({total_days} days)")
    print(f"Present   : {found} date(s)")
    print(f"Missing   : {len(missing)} date(s)")
    print()

    if not missing:
        print("All calendar dates are covered.")
        return

    if args.group_by_month:
        current_month: int | None = None
        for month, day in missing:
            if month != current_month:
                current_month = month
                print(f"--- {MONTH_NAMES[month]} ({month:02d}) ---")
            print(format_date(month, day))
    else:
        for month, day in missing:
            print(format_date(month, day))


if __name__ == "__main__":
    main()
