# backend/app/connectors/calendar/recurrence.py
# 반복 일정 표현을 iCalendar RRULE 문자열로 통일한다.
#  - Google: recurrence 는 본래 ["RRULE:..."] 리스트 → 그대로 변환.
#  - Outlook(Graph): recurrence 는 pattern/range 객체 → 양방향 변환.
# UI 가 제공하는 흔한 경우(매일/매주/평일/매월/매년 + 간격·횟수·종료일)를 지원한다.

_DAY_TO_GRAPH = {
    "MO": "monday",
    "TU": "tuesday",
    "WE": "wednesday",
    "TH": "thursday",
    "FR": "friday",
    "SA": "saturday",
    "SU": "sunday",
}
_GRAPH_TO_DAY = {v: k for k, v in _DAY_TO_GRAPH.items()}
_WD_INDEX = ["MO", "TU", "WE", "TH", "FR", "SA", "SU"]


def parse_rrule(rrule: str) -> dict:
    """'FREQ=WEEKLY;BYDAY=MO,WE;INTERVAL=2' → {FREQ:.., BYDAY:[..], INTERVAL:'2'}."""
    out: dict = {}
    for part in (rrule or "").replace("RRULE:", "").split(";"):
        if "=" not in part:
            continue
        k, v = part.split("=", 1)
        k = k.strip().upper()
        if k == "BYDAY":
            out[k] = [d.strip().upper() for d in v.split(",") if d.strip()]
        else:
            out[k] = v.strip()
    return out


def rrule_to_google(rrule: str) -> list[str]:
    """Google Calendar recurrence 필드(리스트)."""
    if not rrule:
        return []
    body = rrule if rrule.upper().startswith("RRULE:") else f"RRULE:{rrule}"
    return [body]


def rrule_to_graph(rrule: str, date_iso: str) -> dict | None:
    """RRULE + 시작일(YYYY-MM-DD) → Microsoft Graph recurrence 객체."""
    r = parse_rrule(rrule)
    freq = r.get("FREQ", "").upper()
    if not freq:
        return None
    interval = int(r.get("INTERVAL", "1") or 1)
    pattern: dict = {"interval": interval}
    if freq == "DAILY":
        pattern["type"] = "daily"
    elif freq == "WEEKLY":
        pattern["type"] = "weekly"
        days = r.get("BYDAY") or []
        if not days and len(date_iso) >= 10:
            from datetime import date

            days = [_WD_INDEX[date.fromisoformat(date_iso[:10]).weekday()]]
        pattern["daysOfWeek"] = [_DAY_TO_GRAPH[d] for d in days if d in _DAY_TO_GRAPH]
    elif freq == "MONTHLY":
        pattern["type"] = "absoluteMonthly"
        pattern["dayOfMonth"] = int(date_iso[8:10]) if len(date_iso) >= 10 else 1
    elif freq == "YEARLY":
        pattern["type"] = "absoluteYearly"
        pattern["month"] = int(date_iso[5:7]) if len(date_iso) >= 10 else 1
        pattern["dayOfMonth"] = int(date_iso[8:10]) if len(date_iso) >= 10 else 1
    else:
        return None
    rng: dict = {"type": "noEnd", "startDate": date_iso[:10]}
    if r.get("COUNT"):
        rng = {
            "type": "numbered",
            "startDate": date_iso[:10],
            "numberOfOccurrences": int(r["COUNT"]),
        }
    elif r.get("UNTIL"):
        until = r["UNTIL"][:8]  # YYYYMMDD
        if len(until) == 8:
            rng = {
                "type": "endDate",
                "startDate": date_iso[:10],
                "endDate": f"{until[:4]}-{until[4:6]}-{until[6:8]}",
            }
    return {"pattern": pattern, "range": rng}


def graph_to_rrule(recurrence: dict | None) -> str:
    """Graph recurrence 객체 → RRULE 문자열(표시·재동기화용, 베스트 에포트)."""
    if not recurrence:
        return ""
    pat = recurrence.get("pattern") or {}
    rng = recurrence.get("range") or {}
    t = (pat.get("type") or "").lower()
    freq = {
        "daily": "DAILY",
        "weekly": "WEEKLY",
        "absolutemonthly": "MONTHLY",
        "relativemonthly": "MONTHLY",
        "absoluteyearly": "YEARLY",
        "relativeyearly": "YEARLY",
    }.get(t)
    if not freq:
        return ""
    parts = [f"FREQ={freq}"]
    if int(pat.get("interval", 1) or 1) > 1:
        parts.append(f"INTERVAL={int(pat['interval'])}")
    if freq == "WEEKLY" and pat.get("daysOfWeek"):
        days = [_GRAPH_TO_DAY[d] for d in pat["daysOfWeek"] if d in _GRAPH_TO_DAY]
        if days:
            parts.append("BYDAY=" + ",".join(days))
    if (rng.get("type") or "") == "numbered" and rng.get("numberOfOccurrences"):
        parts.append(f"COUNT={int(rng['numberOfOccurrences'])}")
    elif (rng.get("type") or "") == "endDate" and rng.get("endDate"):
        parts.append("UNTIL=" + str(rng["endDate"]).replace("-", "") + "T000000Z")
    return ";".join(parts)
