import { TguApiError } from '../model/tguTypes'
import { toUtcIso } from '../utils/localTime'
import { apiFetch } from './apiFetch'

/**
 * Расчёт комплексного плана (этап 4) напрямую в pcp-complex-mission-service через Vite-прокси
 * (`/api/pcp-complex` → :7002), как и остальные сервисы — без BFF. Это тот самый snapshot,
 * который затем потребляет редактор (stage 5, `calculateSurveys`).
 */
const BASE = '/api/pcp-complex'

/**
 * Максимальная длина интервала расчёта комплексного плана — 10 суток. Дольше считать запрещено
 * (расчёт по всем КА на больший горизонт слишком тяжёлый и теряет смысл для оперативного плана).
 */
export const MAX_COMPLEX_PLAN_RANGE_DAYS = 10
export const MAX_COMPLEX_PLAN_RANGE_MS = MAX_COMPLEX_PLAN_RANGE_DAYS * 24 * 60 * 60 * 1000

/** Статус запуска расчёта комплексного плана (ComplexPlanRunStatus бэка). */
export type ComplexPlanRunStatus = 'CREATED' | 'RUNNING' | 'COMPLETED' | 'FAILED'

export type RunComplexPlanParams = {
  /** Начало интервала расчёта (эпоха-мс, абсолютный момент). */
  fromMs: number
  /** Конец интервала расчёта (эпоха-мс, абсолютный момент). */
  toMs: number
  /** NORAD-id КА, по которым считаем (все эксплуатируемые КА вкладки «Планы»). */
  satelliteIds: number[]
}

/**
 * Ответ синхронного расчёта комплексного плана (ComplexPlanRunResponseDTO).
 * Расчёт уже завершён к моменту ответа: пишет snapshot’ы этапа 4 и возвращает их id + статистику.
 */
export type ComplexPlanRunResult = {
  runId: number
  status: ComplexPlanRunStatus
  intervalStart: string
  intervalEnd: string
  satelliteIds: number[]
  durationMs: number | null
  errorMessage: string | null
  calculatedModesCount: number
  bookedModesCount: number
  complanModesCount: number
  mixedModesCount: number
  affectedSatellitesCount: number
  processedCellsCount: number
  bookedSlotLinksCount: number
  snapshotIds: number[]
  totalRequestsArea: number
  coveredArea: number
  coveredAreaPercent: number
}

/**
 * Краткая карточка прогона из истории расчётов (ComplexPlanRunSummaryDTO).
 * Возвращается списком из GET /api/com-plan/runs, отсортированным по убыванию даты создания.
 */
export type ComplexPlanRunSummary = {
  runId: number
  status: ComplexPlanRunStatus
  intervalStart: string
  intervalEnd: string
  satelliteIds: number[]
  requestedBy: string | null
  createdAt: string
  startedAt: string | null
  finishedAt: string | null
  durationMs: number | null
  errorMessage: string | null
  calculatedModesCount: number
  bookedModesCount: number
  complanModesCount: number
  mixedModesCount: number
  affectedSatellitesCount: number
  processedCellsCount: number
  bookedSlotLinksCount: number
  snapshotIds: number[]
  totalRequestsArea: number
  coveredArea: number
  coveredAreaPercent: number
}

/** Режим съёмки/сброса из результата расчёта (SatelliteModeResponseDTO). Времена приходят из API как UTC ISO и отображаются в локальной зоне браузера. */
export type ComplexPlanMode = {
  id: number
  satelliteId: number
  source: string
  type: 'SURVEY' | 'DROP' | string
  startTime: string
  endTime: string
  revolution: number
  lat: number
  longitude: number
  duration: number
  /** Контур полосы съёмки, WKT POLYGON (lon lat, ...). Для сбросов обычно отсутствует. */
  contourWkt: string | null
  roll: number
  cellNum: number
  bookedSlotIds: number[]
  snapshotId: number | null
  /** Объём режима, МБ (скорость накопления/сброса × длительность). Считает бэк (pcp-types-lib). */
  volumeMb?: number
}

/**
 * Запуск расчёта комплексного плана на интервал по списку КА
 * (pcp-complex-mission-service, POST /api/com-plan/process). Вызов синхронный: возвращает
 * завершённый run со статистикой и id записанных snapshot’ов. Бэк отклоняет запуск, если по
 * одному из КА уже идёт пересекающийся расчёт.
 * @param params Интервал расчёта и список КА.
 *
 * @returns Завершённый прогон со статистикой и id записанных snapshot’ов.
 */
export async function runComplexPlan(params: RunComplexPlanParams): Promise<ComplexPlanRunResult> {
  const body = {
    intervalStart: toUtcIso(params.fromMs),
    intervalEnd: toUtcIso(params.toMs),
    satelliteIds: params.satelliteIds,
  }

  const url = `${BASE}/api/com-plan/process`
  let response: Response
  try {
    response = await apiFetch(url, {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
        'X-Requested-By': 'pcp-tgu-ops-ui',
      },
      body: JSON.stringify(body),
    })
  } catch {
    throw new TguApiError('Не удалось подключиться к сервису комплексного плана.', 'network')
  }

  const text = await response.text()
  if (!response.ok) {
    throw new TguApiError(
      extractErrorText(text) || 'Не удалось рассчитать комплексный план.',
      'http',
      response.status,
    )
  }
  if (!text.trim()) {
    throw new TguApiError('Сервис комплексного плана вернул пустой ответ.', 'http', response.status)
  }

  return JSON.parse(text) as ComplexPlanRunResult
}

/**
 * История прогонов комплексного плана (pcp-complex-mission-service, GET /api/com-plan/runs).
 * Список отсортирован бэком по убыванию даты создания, поэтому первый завершённый элемент —
 * это последний построенный комплексный план.
 * @returns История прогонов комплексного плана (по убыванию даты создания).
 */
export async function fetchComplexPlanRuns(): Promise<ComplexPlanRunSummary[]> {
  const url = `${BASE}/api/com-plan/runs`
  let response: Response
  try {
    response = await apiFetch(url, { method: 'GET', headers: { Accept: 'application/json' } })
  } catch {
    throw new TguApiError('Не удалось подключиться к сервису комплексного плана.', 'network')
  }
  const text = await response.text()
  if (!response.ok) {
    throw new TguApiError(
      extractErrorText(text) || 'Не удалось загрузить историю расчётов.',
      'http',
      response.status,
    )
  }
  if (!text.trim()) return []
  return JSON.parse(text) as ComplexPlanRunSummary[]
}

/**
 * Режимы (съёмки/сбросы) рассчитанного run’а для отрисовки на карте
 * (pcp-complex-mission-service, GET /api/com-plan/runs/{runId}/modes).
 * @param runId Идентификатор прогона расчёта.
 *
 * @returns Режимы (съёмки/сбросы) прогона для отрисовки на карте.
 */
export async function fetchComplexPlanRunModes(runId: number): Promise<ComplexPlanMode[]> {
  const url = `${BASE}/api/com-plan/runs/${encodeURIComponent(runId)}/modes`
  let response: Response
  try {
    response = await apiFetch(url, { method: 'GET', headers: { Accept: 'application/json' } })
  } catch {
    throw new TguApiError('Не удалось подключиться к сервису комплексного плана.', 'network')
  }
  const text = await response.text()
  if (!response.ok) {
    throw new TguApiError(
      extractErrorText(text) || 'Не удалось загрузить результат расчёта.',
      'http',
      response.status,
    )
  }
  if (!text.trim()) return []
  return JSON.parse(text) as ComplexPlanMode[]
}

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 ['message', 'error', 'reason', 'detail']) {
      const value = parsed[field]
      if (typeof value === 'string' && value.trim()) {
        return value
      }
    }
  } catch {
    return trimmed
  }
  return trimmed
}
