import { NextResponse, NextRequest } from 'next/server' import { getServerSession } from 'next-auth' import { authOptions } from '@/lib/auth' import { getToken } from 'next-auth/jwt' export async function GET(req: NextRequest) { try { const session = await getServerSession(authOptions) const authHeader = req.headers.get('authorization') || req.headers.get('Authorization') const bearer = authHeader && authHeader.toLowerCase().startsWith('bearer ') ? authHeader.slice(7) : undefined const secret = process.env.NEXTAUTH_SECRET const token = secret ? (await getToken({ req, secret }).catch(() => null)) : null let accessToken: string | undefined = session?.accessToken || bearer || (token as any)?.accessToken const refreshToken: string | undefined = session?.refreshToken || (token as any)?.refreshToken if (!accessToken && refreshToken) { try { const refreshRes = await fetch(`${process.env.BACKEND_URL}/auth/refresh/`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ refresh: refreshToken }), }) if (refreshRes.ok) { const refreshed = await refreshRes.json() accessToken = refreshed.access } else { const errorText = await refreshRes.text() let errorData: { error?: string; detail?: string; code?: string } = {} try { errorData = JSON.parse(errorText) } catch { errorData = { error: errorText } } const errorMessage = (errorData.error as string) || (errorData.detail as string) || '' if (typeof errorMessage === 'string' && (errorMessage.includes('Token is expired') || errorMessage.includes('expired') || errorData.code === 'token_not_valid')) { console.warn('Refresh token expired, user needs to re-authenticate') } else { console.error('Token refresh failed:', errorData.error || errorData.detail || 'Unknown error') } } } catch (error) { console.error('Error during token refresh:', error) } } if (!accessToken) { return NextResponse.json({ success: false, error: 'Unauthorized' }, { status: 401 }) } const backendUrl = process.env.BACKEND_URL if (!backendUrl) { return NextResponse.json({ success: false, error: 'BACKEND_URL is not configured' }, { status: 500 }) } const { searchParams } = new URL(req.url) const objectId = searchParams.get('objectId') if (!objectId) { return NextResponse.json({ success: false, error: 'objectId query parameter is required' }, { status: 400 }) } // Нормализуем objectId с фронтенда вида "object_2" к числовому идентификатору бэкенда "2" const normalizedObjectId = /^object_(\d+)$/.test(objectId) ? objectId.replace(/^object_/, '') : objectId const zonesRes = await fetch(`${backendUrl}/account/get-zones/?objectId=${encodeURIComponent(normalizedObjectId)}`, { headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', Authorization: `Bearer ${accessToken}`, }, cache: 'no-store', }) const payloadText = await zonesRes.text() let payload: any try { payload = JSON.parse(payloadText) } catch { payload = payloadText } // Отладка: наблюдаем статус ответа и предполагаемую длину console.log( '[api/get-zones] objectId=%s normalized=%s status=%d payloadType=%s length=%d', objectId, normalizedObjectId, zonesRes.status, typeof payload, Array.isArray((payload as any)?.data) ? (payload as any).data.length : Array.isArray(payload) ? payload.length : 0 ) if (!zonesRes.ok) { if (payload && typeof payload === 'object') { if (payload.code === 'token_not_valid' || (payload.detail && typeof payload.detail === 'string' && (payload.detail.includes('Token is expired') || payload.detail.includes('Given token not valid'))) || (payload.messages && Array.isArray(payload.messages) && payload.messages.some((msg: any) => msg.message && typeof msg.message === 'string' && msg.message.includes('Token is expired') ))) { console.warn('Access token expired, user needs to re-authenticate') return NextResponse.json({ success: false, error: 'Authentication required - please log in again' }, { status: 401 }) } } // Резервный путь: пробуем получить список объектов и извлечь зоны для указанного objectId try { const objectsRes = await fetch(`${backendUrl}/account/get-objects/`, { headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', Authorization: `Bearer ${accessToken}`, }, cache: 'no-store', }) const objectsText = await objectsRes.text() let objectsPayload: any try { objectsPayload = JSON.parse(objectsText) } catch { objectsPayload = objectsText } if (objectsRes.ok) { const objectsList: any[] = Array.isArray(objectsPayload?.data) ? objectsPayload.data : (Array.isArray(objectsPayload) ? objectsPayload : (Array.isArray(objectsPayload?.objects) ? objectsPayload.objects : [])) const target = objectsList.find((o: any) => ( o?.id === normalizedObjectId || o?.object_id === normalizedObjectId || o?.slug === normalizedObjectId || o?.identifier === normalizedObjectId )) const rawZones: any[] = target?.zones || target?.zone_list || target?.areas || target?.Зоны || [] const normalized = Array.isArray(rawZones) ? rawZones.map((z: any, idx: number) => ({ id: z?.id ?? z?.zone_id ?? `${normalizedObjectId}_zone_${idx}`, name: z?.name ?? z?.zone_name ?? `Зона ${idx + 1}`, floor: typeof z?.floor === 'number' ? z.floor : (typeof z?.level === 'number' ? z.level : 0), image_path: z?.image_path ?? z?.image ?? z?.preview_image ?? null, model_path: z?.model_path ?? z?.model ?? z?.modelUrl ?? null, order: typeof z?.order === 'number' ? z.order : 0, sensors: Array.isArray(z?.sensors) ? z.sensors : (Array.isArray(z?.detectors) ? z.detectors : []), })) : [] // Отладка: длина массива в резервном пути console.log('[api/get-zones:fallback] normalized length=%d', normalized.length) // Возвращаем успешный ответ с нормализованными зонами (может быть пустой массив) return NextResponse.json({ success: true, data: normalized }, { status: 200 }) } } catch (fallbackErr) { console.warn('Fallback get-objects failed:', fallbackErr) } // Если дошли до сюда, возвращаем успешный ответ с пустым списком, чтобы не ломать UI return NextResponse.json({ success: true, data: [] }, { status: 200 }) } // Распаковываем массив зон от бэкенда в плоский список в поле data const zonesData: any[] = Array.isArray((payload as any)?.data) ? (payload as any).data : Array.isArray(payload) ? (payload as any) : Array.isArray((payload as any)?.zones) ? (payload as any).zones : [] return NextResponse.json({ success: true, data: zonesData }, { status: 200 }) // Нормализация: при необходимости используем запасной image_path на стороне клиента return NextResponse.json({ success: true, data: payload }) } catch (error) { console.error('Error fetching zones data:', error) return NextResponse.json( { success: false, error: 'Failed to fetch zones data', }, { status: 500 } ) } }