# backend/app/routers/calendar.py
import re
import uuid

from fastapi import APIRouter, Depends, HTTPException
from sqlmodel import Session, select

from ..connectors import get_calendar_connector
from ..db import get_session
from ..models import Calendar, CalEvent, FocusBlock, Meeting, MeetingAction, Task
from ..schemas import (
    CalendarOut,
    CalEventOut,
    DayBundleOut,
    EventActionOut,
    FocusBlockOut,
    FocusSuggestRequest,
    FocusSuggestResponse,
    MaterializeResponse,
    MeetingActionOut,
    MeetingOut,
    WeekBundleOut,
)
from ..services.focus import suggest_focus
from ..services.meetings import assemble_meeting, materialize_action, materialize_all
from .tasks import to_node  # phase-2 TaskNode 빌더 재사용

router = APIRouter()  # prefix 없음. main.py 에서 prefix="/api" 등록.

WEEK = [7, 8, 9, 10, 11, 12, 13]
WEEKDAYS = ["일", "월", "화", "수", "목", "금", "토"]
TODAY = 8


def _end_from(start: str, dur: int) -> str:
    h, m = map(int, start.split(":"))
    total = h * 60 + m + dur
    return f"{total // 60:02d}:{total % 60:02d}"


def meet_label(m: Meeting | None) -> str:
    if m is None:
        return ""
    phase = getattr(m.phase, "value", m.phase)
    if m.one_on_one:
        return "1:1 어시스턴트 브리핑"
    if phase == "upcoming":
        return "사전 브리핑 보기"
    if phase == "live":
        return "실시간 기록 보기"
    return "회의 노트 · 액션 보기"


def _parse_day(ev: dict) -> int:
    """ev 에서 6월 날짜(int) 추출. 'date'가 'M/D'면 일(D), 'day'가 숫자면 그 값, 아니면 TODAY."""
    date_str = str(ev.get("date") or "")
    if "/" in date_str:
        try:
            return int(date_str.split("/")[1])
        except (ValueError, IndexError):
            pass
    try:
        return int(ev.get("day"))
    except (TypeError, ValueError):
        return TODAY


def create_event_from_extract(s: Session, ev: dict, source: str) -> str:
    """메일→일정 federation 헬퍼. ev = {title, date|day, time, dur, place?} →
    CalEvent 생성(연합 출처 source 기록) 후 id 반환. phase-9 routers/mail.py 가 import.
    메일 AI 이벤트(date='6/10', day='오늘', time='14:00'|'종일')도 견고하게 처리."""
    eid = "ce-" + uuid.uuid4().hex[:8]
    day = _parse_day(ev)
    m = re.match(r"(\d{1,2}):(\d{2})", str(ev.get("time") or ""))
    if m:
        start = f"{int(m.group(1)):02d}:{m.group(2)}"
        dur_digits = re.sub(r"\D", "", str(ev.get("dur") or "")) or "60"
        end = _end_from(start, int(dur_digits))
    else:  # 종일/미정 시간
        start, end = "09:00", "09:30"
    conn = get_calendar_connector()
    conn.write_event(
        s,
        dict(
            id=eid,
            day=day,
            start=start,
            end=end,
            title=ev["title"],
            cal="meeting",
            loc=ev.get("place", ""),
            note=f"연합 출처: {source}",
            soon=False,
            people="",
            sort_order=0,
        ),
    )
    return eid


def _event_out(s: Session, e: CalEvent) -> CalEventOut:
    m = s.get(Meeting, e.id)
    eacts = s.exec(
        select(MeetingAction)
        .where(MeetingAction.event_id == e.id, MeetingAction.source == "event")
        .order_by(MeetingAction.idx)
    ).all()
    return CalEventOut(
        id=e.id,
        day=e.day,
        start=e.start,
        end=e.end,
        title=e.title,
        cal=e.cal,
        loc=e.loc,
        note=e.note,
        soon=e.soon,
        people=[p.strip() for p in e.people.split(",") if p.strip()],
        actions=[EventActionOut(text=a.text, when=a.when_text) for a in eacts],
        has_meeting=m is not None,
        meet_label=meet_label(m),
    )


@router.get("/calendar/week", response_model=WeekBundleOut)
def get_week(s: Session = Depends(get_session)):
    conn = get_calendar_connector()  # mock-first
    rows = [s.get(CalEvent, r["id"]) for r in conn.list_events(s)]
    cals = s.exec(select(Calendar).order_by(Calendar.sort_order)).all()
    counts: dict[str, int] = {}
    for e in rows:
        counts[e.cal] = counts.get(e.cal, 0) + 1
    fbs = s.exec(select(FocusBlock).order_by(FocusBlock.sort_order)).all()
    return WeekBundleOut(
        today=TODAY,
        week=WEEK,
        weekdays=WEEKDAYS,
        calendars=[
            CalendarOut(id=c.id, name=c.name, tone=c.tone, on=c.on, count=counts.get(c.id, 0))
            for c in cals
        ],
        events=[_event_out(s, e) for e in rows],
        focus_blocks=[FocusBlockOut(**f.model_dump()) for f in fbs],
    )


@router.get("/calendar/day/{day}", response_model=DayBundleOut)
def get_day(day: int, s: Session = Depends(get_session)):
    evs = s.exec(select(CalEvent).where(CalEvent.day == day).order_by(CalEvent.start)).all()
    fbs = s.exec(select(FocusBlock).where(FocusBlock.day == day).order_by(FocusBlock.start)).all()
    return DayBundleOut(
        day=day,
        events=[_event_out(s, e) for e in evs],
        focus_blocks=[FocusBlockOut(**f.model_dump()) for f in fbs],
    )


@router.get("/calendar/meetings/{mid}", response_model=MeetingOut)
def get_meeting(mid: str, s: Session = Depends(get_session)):
    data = assemble_meeting(s, mid)
    if data is None:
        raise HTTPException(404, "meeting not found")
    return MeetingOut(**data)


@router.post(
    "/calendar/meetings/{mid}/actions/{idx}/materialize", response_model=MaterializeResponse
)
def materialize_one(mid: str, idx: int, s: Session = Depends(get_session)):
    try:
        action, task = materialize_action(s, mid, idx)
    except ValueError as e:
        raise HTTPException(404, "action not found") from e
    remaining = s.exec(
        select(MeetingAction).where(
            MeetingAction.meeting_id == mid, MeetingAction.added == False  # noqa: E712
        )
    ).all()
    all_tasks = s.exec(select(Task)).all()
    return MaterializeResponse(
        action=MeetingActionOut(
            id=action.id,
            idx=action.idx,
            text=action.text,
            who=action.who,
            when=action.when_text,
            added=action.added,
            materialized_task_id=action.materialized_task_id,
        ),
        task=to_node(s, task, all_tasks),
        all_added=len(remaining) == 0,
    )


@router.post(
    "/calendar/meetings/{mid}/actions/materialize-all",
    response_model=list[MaterializeResponse],
)
def materialize_remaining(mid: str, s: Session = Depends(get_session)):
    pairs = materialize_all(s, mid)
    all_tasks = s.exec(select(Task)).all()
    return [
        MaterializeResponse(
            action=MeetingActionOut(
                id=a.id,
                idx=a.idx,
                text=a.text,
                who=a.who,
                when=a.when_text,
                added=a.added,
                materialized_task_id=a.materialized_task_id,
            ),
            task=to_node(s, t, all_tasks),
            all_added=True,
        )
        for a, t in pairs
    ]


@router.post("/calendar/focus/suggest", response_model=FocusSuggestResponse)
def focus_suggest(body: FocusSuggestRequest, s: Session = Depends(get_session)):
    blocks = suggest_focus(s, body.day, body.min_minutes)
    # commit 전에 스냅샷(커밋 후 객체 expire 방지)
    out = [FocusBlockOut(**b.model_dump()) for b in blocks]
    if body.create:
        for b in blocks:
            s.add(b)
        s.commit()
    return FocusSuggestResponse(day=body.day, created=body.create, suggestions=out)
