import os
import requests
from datetime import datetime, date, time, timedelta, timezone
from zoneinfo import ZoneInfo
from pathlib import Path

MEALIE_ENDPOINT = os.getenv("MEALIE_ENDPOINT", "http://192.168.1.97:9925").rstrip("/")
MEALIE_API_KEY = os.getenv("MEALIE_API_KEY", "")
TIMEZONE = os.getenv("TIMEZONE", "Europe/Paris")
OUTPUT_ICS = os.getenv("OUTPUT_ICS", "/data/calendar.ics")
CALENDAR_NAME = os.getenv("CALENDAR_NAME", "Courses hebdo")
WEEKDAY = int(os.getenv("WEEKDAY", "4"))
EVENT_HOUR = int(os.getenv("EVENT_HOUR", "19"))
EVENT_MINUTE = int(os.getenv("EVENT_MINUTE", "0"))
EVENT_DURATION_MIN = int(os.getenv("EVENT_DURATION_MIN", "60"))
LOOKAHEAD_DAYS = int(os.getenv("LOOKAHEAD_DAYS", "14"))

HEADERS = {"Authorization": f"Bearer {MEALIE_API_KEY}"} if MEALIE_API_KEY else {}
TZ = ZoneInfo(TIMEZONE)

def ics_escape(s):
    return s.replace("\\", "\\\\").replace(";", "\\;").replace(",", "\\,").replace("\n", "\\n").replace("\r", "")

def fmt_dt(dt):
    return dt.astimezone(timezone.utc).strftime("%Y%m%dT%H%M%SZ")

def get_json(path, params=None):
    r = requests.get(f"{MEALIE_ENDPOINT}{path}", headers=HEADERS, params=params, timeout=30)
    r.raise_for_status()
    return r.json()

def first_present(d, keys, default=""):
    for k in keys:
        v = d.get(k)
        if v:
            return v
    return default

def fetch_items():
    today = date.today()
    end = today + timedelta(days=LOOKAHEAD_DAYS)
    candidates = []
    for path in ("/api/households/mealplans", "/api/households/mealplans/today"):
        try:
            params = {"start_date": today.isoformat(), "end_date": end.isoformat()} if path.endswith("mealplans") else None
            data = get_json(path, params=params)
            if isinstance(data, list):
                candidates.extend(data)
            elif isinstance(data, dict):
                candidates.extend(data.get("items", []) or data.get("results", []) or [])
        except Exception:
            pass
    return candidates

def meal_title(item):
    recipe = item.get("recipe") or {}
    return first_present(recipe, ["name", "title"], "Meal")

def meal_date(item):
    for k in ["date", "mealDate", "plannedAt", "scheduled_at", "start"]:
        v = item.get(k)
        if v:
            for candidate in (v.replace("Z", "+00:00"), v):
                try:
                    return datetime.fromisoformat(candidate).date()
                except Exception:
                    pass
    return None

def build_events(items):
    events = []
    for item in items:
        d = meal_date(item)
        if not d or d.weekday() != WEEKDAY:
            continue
        start = datetime.combine(d, time(EVENT_HOUR, EVENT_MINUTE), TZ)
        end = start + timedelta(minutes=EVENT_DURATION_MIN)
        title = f"Courses - {meal_title(item)}"
        desc = f"Mealie meal plan\\n{MEALIE_ENDPOINT}\\n"
        events.append((start, end, title, desc))
    if events:
        return events
    d = date.today()
    days_ahead = (WEEKDAY - d.weekday()) % 7
    if days_ahead == 0:
        days_ahead = 7
    d = d + timedelta(days=days_ahead)
    start = datetime.combine(d, time(EVENT_HOUR, EVENT_MINUTE), TZ)
    end = start + timedelta(minutes=EVENT_DURATION_MIN)
    events.append((start, end, CALENDAR_NAME, "Weekly shopping reminder"))
    return events

def make_ics(events):
    now = datetime.now(timezone.utc)
    lines = [
        "BEGIN:VCALENDAR",
        "VERSION:2.0",
        "PRODID:-//Mealie Shopping Calendar//FR//EN",
        "CALSCALE:GREGORIAN",
        "METHOD:PUBLISH",
    ]
    for idx, (start, end, title, desc) in enumerate(events, start=1):
        uid = f"{fmt_dt(now)}-{idx}@mealie-shopping"
        lines += [
            "BEGIN:VEVENT",
            f"UID:{uid}",
            f"DTSTAMP:{fmt_dt(now)}",
            f"SUMMARY:{ics_escape(title)}",
            f"DESCRIPTION:{ics_escape(desc)}",
            f"DTSTART:{fmt_dt(start)}",
            f"DTEND:{fmt_dt(end)}",
            "STATUS:CONFIRMED",
            "END:VEVENT",
        ]
    lines.append("END:VCALENDAR")
    return "\r\n".join(lines) + "\r\n"

def main():
    items = fetch_items()
    events = build_events(items)
    p = Path(OUTPUT_ICS)
    p.parent.mkdir(parents=True, exist_ok=True)
    p.write_text(make_ics(events), encoding="utf-8")
    print(f"wrote {p} with {len(events)} event(s)")

if __name__ == "__main__":
    main()
