export const dynamic = 'force-dynamic' export const runtime = 'nodejs' import { NextResponse } from 'next/server' import { isBearerAuthorized, unauthorized, internalHeaders } from '@/lib/voice-tools' const baseUrl = () => `http://localhost:${process.env.PORT || '3000'}` // Resolve agent-style owner to the Google calendar id used by /api/calendar. // daniil → primary env DANIIL_CALENDAR_ID or default address // sveta → SVETA_CALENDAR_ID function calendarIdFor(owner: string): string { const o = (owner || '').toLowerCase() if (o === 'sveta' || o === 'света' || o === 'lusya') { return process.env.SVETA_CALENDAR_ID || '' } return process.env.DANIIL_CALENDAR_ID || 'daniilklimov25@gmail.com' } function ownerTag(owner: string): 'daniil' | 'sveta' { const o = (owner || '').toLowerCase() if (o === 'sveta' || o === 'света' || o === 'lusya') return 'sveta' return 'daniil' } // ─────────── GET ─────────── list events export async function GET(req: Request) { if (!isBearerAuthorized(req)) return unauthorized() const { searchParams } = new URL(req.url) const range = searchParams.get('range') || 'today' // today | week | month let url = `${baseUrl()}/api/calendar?range=${encodeURIComponent(range)}` // For month: forward year/month if supplied if (range === 'month') { const year = searchParams.get('year') const month = searchParams.get('month') if (year) url += `&year=${encodeURIComponent(year)}` if (month) url += `&month=${encodeURIComponent(month)}` } const r = await fetch(url, { cache: 'no-store', headers: internalHeaders() }).catch(() => null) if (!r || !r.ok) return NextResponse.json({ events: [], error: 'unreachable' }, { status: 502 }) const j = await r.json() const events = (j.events || []).map((e: any) => ({ id: e.id, title: e.title, start: e.start, end: e.end, all_day: e.allDay, owner: e.owner, // 'daniil' | 'sveta' owner_name: e.ownerName, })) return NextResponse.json({ events }) } // ─────────── POST ─────────── create event export async function POST(req: Request) { if (!isBearerAuthorized(req)) return unauthorized() const body = await req.json().catch(() => null) if (!body) return NextResponse.json({ error: 'body required' }, { status: 400 }) const title = typeof body.title === 'string' ? body.title.trim() : '' const date = typeof body.date === 'string' ? body.date.trim() : '' const owner = ownerTag(body.owner || 'daniil') const all_day = Boolean(body.all_day) const start_time = typeof body.start_time === 'string' ? body.start_time.trim() : '' const end_time = typeof body.end_time === 'string' ? body.end_time.trim() : '' if (!title || !date) { return NextResponse.json({ error: 'title and date required' }, { status: 400 }) } const payload: Record = { title, date, allDay: all_day, owner, } if (!all_day) { payload.startTime = start_time || '12:00' // Default end = start + 1 hour if (end_time) { payload.endTime = end_time } else { const [h, m] = (start_time || '12:00').split(':').map((n: string) => parseInt(n, 10)) const endH = (h + 1) % 24 payload.endTime = `${endH.toString().padStart(2, '0')}:${(m || 0).toString().padStart(2, '0')}` } } const r = await fetch(`${baseUrl()}/api/calendar`, { method: 'POST', headers: { ...internalHeaders(), 'Content-Type': 'application/json' }, body: JSON.stringify(payload), cache: 'no-store', }).catch(() => null) if (!r || !r.ok) { const detail = r ? await r.text().catch(() => '') : '' return NextResponse.json({ error: 'create_failed', detail: detail.slice(0, 300) }, { status: 502 }) } const j = await r.json() if (j.error) return NextResponse.json({ error: j.error }, { status: 502 }) return NextResponse.json({ event: j.event }) } // ─────────── PUT ─────────── update event export async function PUT(req: Request) { if (!isBearerAuthorized(req)) return unauthorized() const body = await req.json().catch(() => null) if (!body) return NextResponse.json({ error: 'body required' }, { status: 400 }) const event_id = typeof body.event_id === 'string' ? body.event_id : '' if (!event_id) return NextResponse.json({ error: 'event_id required' }, { status: 400 }) const owner = ownerTag(body.owner || 'daniil') const calendarId = calendarIdFor(owner) const payload: Record = { eventId: event_id, calendarId, allDay: Boolean(body.all_day), } if (typeof body.title === 'string') payload.title = body.title.trim() if (typeof body.date === 'string') payload.date = body.date.trim() if (typeof body.start_time === 'string') payload.startTime = body.start_time.trim() if (typeof body.end_time === 'string') payload.endTime = body.end_time.trim() const r = await fetch(`${baseUrl()}/api/calendar`, { method: 'PUT', headers: { ...internalHeaders(), 'Content-Type': 'application/json' }, body: JSON.stringify(payload), cache: 'no-store', }).catch(() => null) if (!r || !r.ok) { const detail = r ? await r.text().catch(() => '') : '' return NextResponse.json({ error: 'update_failed', detail: detail.slice(0, 300) }, { status: 502 }) } const j = await r.json() if (j.error) return NextResponse.json({ error: j.error }, { status: 502 }) return NextResponse.json({ event: j.event }) } // ─────────── DELETE ─────────── delete event export async function DELETE(req: Request) { if (!isBearerAuthorized(req)) return unauthorized() const { searchParams } = new URL(req.url) const event_id = searchParams.get('event_id') || '' const owner = searchParams.get('owner') || 'daniil' if (!event_id) return NextResponse.json({ error: 'event_id required' }, { status: 400 }) const calendarId = calendarIdFor(owner) const url = `${baseUrl()}/api/calendar?eventId=${encodeURIComponent(event_id)}&calendarId=${encodeURIComponent(calendarId)}` const r = await fetch(url, { method: 'DELETE', headers: internalHeaders(), cache: 'no-store', }).catch(() => null) if (!r || !r.ok) { const detail = r ? await r.text().catch(() => '') : '' return NextResponse.json({ error: 'delete_failed', detail: detail.slice(0, 300) }, { status: 502 }) } return NextResponse.json({ deleted: true }) }