import {
  TguApiError,
  type TguPlan,
  type TguPlanDecision,
  type TguPlanDecisionMessage,
  type TguPlatform,
} from '../model/tguTypes'
import { apiFetch } from './apiFetch'

/**
 * Запросы планирования ТГУ идут напрямую в pcp-tgu-service через gateway (`/api/pcp-tgu` →
 * :7011), как и остальные tgu-вызовы (см. tguPlanApi.ts). Решение/подтверждение закладки —
 * на тест-контроллере ТГУ (`/test/tgu/*`, гейт `tgu.test-controller.enabled`, MVP-канал).
 */
const BASE = '/api/pcp-tgu'

/**
 * Список платформ (КА) ТГУ.
 * @returns Платформы планирования ТГУ.
 */
export async function fetchPlatforms(): Promise<TguPlatform[]> {
  return fetchJson<TguPlatform[]>(`${BASE}/api/platforms`)
}

/**
 * Планы ТГУ с заданной глубиной истории, опционально по одному КА.
 * @param historyDays Глубина истории в сутках.
 * @param spacecraftId Идентификатор КА для фильтра (необязателен — иначе по всем КА).
 *
 * @returns Планы ТГУ.
 */
export async function fetchPlans(historyDays: number, spacecraftId?: string): Promise<TguPlan[]> {
  const query = new URLSearchParams({ historyDays: String(historyDays) })
  const path = spacecraftId
    ? `${BASE}/api/plans/${encodeURIComponent(spacecraftId)}?${query}`
    : `${BASE}/api/plans?${query}`

  return fetchJson<TguPlan[]>(path)
}

/**
 * Отправляет решение оператора по плану (принять/отклонить и т.п.).
 * @param planId Идентификатор плана.
 * @param decision Решение по плану.
 * @param reason Причина решения (необязательна).
 *
 * @returns Сообщение-результат обработки решения.
 */
export async function sendPlanDecision(
  planId: string,
  decision: TguPlanDecision,
  reason?: string,
): Promise<TguPlanDecisionMessage> {
  const query = new URLSearchParams({ decision })
  if (reason?.trim()) {
    query.set('reason', reason.trim())
  }

  return fetchJson<TguPlanDecisionMessage>(
    `${BASE}/test/tgu/plans/${encodeURIComponent(planId)}/decision?${query}`,
    { method: 'POST' },
    true,
  )
}

/**
 * «Снять с учёта» терминально-негативный план: он перестаёт считаться проблемой и красить
 * индикатор КА. Статус и цепочку не трогает; обратимо ([restorePlan]). 422 — статус не снимаемый.
 * @param planId Идентификатор плана.
 */
export async function dismissPlan(planId: string): Promise<void> {
  await fetchJson<void>(`${BASE}/api/plans/${encodeURIComponent(planId)}/dismiss`, {
    method: 'POST',
  })
}

/**
 * «Вернуть на учёт» ранее снятый план.
 * @param planId Идентификатор плана.
 */
export async function restorePlan(planId: string): Promise<void> {
  await fetchJson<void>(`${BASE}/api/plans/${encodeURIComponent(planId)}/restore`, {
    method: 'POST',
  })
}

/**
 * ТЕСТ: подтверждает закладку плана (AWAITING_LAYIN → LAID_IN) через тест-контроллер ТГУ.
 * decisionRequest=false — пробрасываем реальный текст ошибки бэка (напр. гард «закладка ±10 мин»).
 * @param planId Идентификатор плана.
 */
export async function confirmPlanLayin(planId: string): Promise<void> {
  await fetchJson<void>(`${BASE}/test/tgu/plans/${encodeURIComponent(planId)}/confirm-layin`, {
    method: 'POST',
  })
}

async function fetchJson<T>(url: string, init?: RequestInit, decisionRequest = false): Promise<T> {
  let response: Response
  try {
    response = await apiFetch(url, {
      headers: { Accept: 'application/json' },
      ...init,
    })
  } catch {
    throw new TguApiError('Не удалось подключиться к backend API.', 'network')
  }

  const text = await response.text()
  if (!response.ok) {
    throw new TguApiError(
      errorMessage(response.status, text, decisionRequest),
      'http',
      response.status,
    )
  }

  if (!text.trim()) {
    return undefined as T
  }

  return JSON.parse(text) as T
}

function errorMessage(status: number, body: string, decisionRequest: boolean): string {
  if (decisionRequest && status === 404) {
    return 'План не найден.'
  }
  if (decisionRequest && status === 409) {
    return 'План не является активным планом, ожидающим решения, или для него нет active attempt.'
  }
  if (decisionRequest && status >= 500) {
    return 'Ошибка сервиса при отправке решения.'
  }

  return extractErrorText(body) || 'Ошибка backend API.'
}

function extractErrorText(body: string): string {
  const trimmed = body.trim()
  if (!trimmed) return ''

  try {
    const parsed = JSON.parse(trimmed) as Record<string, unknown>
    for (const field of ['reason', 'message', 'error', 'detail']) {
      const value = parsed[field]
      if (typeof value === 'string' && value.trim()) {
        return value
      }
    }
  } catch {
    return trimmed
  }

  return trimmed
}
