import type {
  CreateRequestPayload,
  CreateRequestResult,
  RequestFilter,
  RequestMapItem,
} from '../model/requestTypes'
import { apiFetch } from './apiFetch'

const BASE = '/api/pcp-request/v1'
const PAGE_SIZE = 500
const MAX_PAGES = 10 // up to 5000 requests

type WithGeometryPage = {
  items: RequestMapItem[]
  page: number
  size: number
  totalItems: number
  totalPages: number
}

async function fetchWithGeometryPage(
  filter: RequestFilter,
  page: number,
): Promise<WithGeometryPage> {
  const params = new URLSearchParams()
  if (filter.beginFrom) params.set('beginFrom', filter.beginFrom)
  if (filter.beginTo) params.set('beginTo', filter.beginTo)
  if (filter.endFrom) params.set('endFrom', filter.endFrom)
  if (filter.endTo) params.set('endTo', filter.endTo)
  if (filter.status) params.set('status', filter.status)
  if (filter.surveyType) params.set('surveyType', filter.surveyType)
  params.set('size', String(PAGE_SIZE))
  params.set('page', String(page))
  params.set('sort', 'beginDateTime,asc')

  const response = await apiFetch(`${BASE}/requests/map?${params}`, {
    headers: { Accept: 'application/json' },
  })

  if (!response.ok) {
    throw new Error(`Ошибка загрузки заявок: ${response.status}`)
  }

  return response.json() as Promise<WithGeometryPage>
}

/**
 * Загружает заявки для карты постранично (до MAX_PAGES страниц) и склеивает их в один список.
 * @param filter Фильтр заявок (даты, статус, тип съёмки).
 * @param onProgress Колбэк прогресса (загружено, всего); необязателен.
 *
 * @returns Список заявок, общее число и флаг усечения по лимиту страниц.
 */
export async function fetchRequestsForMap(
  filter: RequestFilter,
  onProgress?: (loaded: number, total: number) => void,
): Promise<{ items: RequestMapItem[]; totalItems: number; truncated: boolean }> {
  const first = await fetchWithGeometryPage(filter, 0)
  onProgress?.(first.items.length, first.totalItems)

  if (first.totalPages <= 1) {
    return { items: first.items, totalItems: first.totalItems, truncated: false }
  }

  const pagesToLoad = Math.min(first.totalPages, MAX_PAGES) - 1
  const remaining = await Promise.all(
    Array.from({ length: pagesToLoad }, (_, i) => fetchWithGeometryPage(filter, i + 1)),
  )

  const allItems = [...first.items, ...remaining.flatMap((page) => page.items)]
  onProgress?.(allItems.length, first.totalItems)

  return {
    items: allItems,
    totalItems: first.totalItems,
    truncated: first.totalPages > MAX_PAGES,
  }
}

type ErrorDetail = { field?: string; message?: string }
type ErrorBody = { code?: string; message?: string; details?: ErrorDetail[] }

async function readErrorMessage(response: Response, fallback: string): Promise<string> {
  try {
    const body = (await response.json()) as ErrorBody
    const details = body.details
      ?.map((d) => (d.field ? `${d.field}: ${d.message}` : d.message))
      .filter(Boolean)
    const detailText = details && details.length > 0 ? ` (${details.join('; ')})` : ''
    if (body.message) return `${body.message}${detailText}`
  } catch {
    // тело ответа не JSON — используем fallback
  }
  return `${fallback}: ${response.status}`
}

/**
 * Создаёт заявку (pcp-request-service, POST /requests).
 * @param payload Данные новой заявки.
 *
 * @returns Результат создания заявки.
 */
export async function createRequest(payload: CreateRequestPayload): Promise<CreateRequestResult> {
  const response = await apiFetch(`${BASE}/requests`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
    body: JSON.stringify(payload),
  })

  if (!response.ok) {
    throw new Error(await readErrorMessage(response, 'Не удалось создать заявку'))
  }

  return response.json() as Promise<CreateRequestResult>
}

/**
 * Удаляет заявку по идентификатору (pcp-request-service, DELETE /requests/{id}).
 * @param id Идентификатор заявки.
 */
export async function deleteRequest(id: string): Promise<void> {
  const response = await apiFetch(`${BASE}/requests/${encodeURIComponent(id)}`, {
    method: 'DELETE',
    headers: { Accept: 'application/json' },
  })

  if (!response.ok) {
    throw new Error(await readErrorMessage(response, 'Не удалось удалить заявку'))
  }
}
