import { TguApiError } from "../model/tguTypes";

const BASE = "/api/pcp-ballistics";

export type PointVisibilityParam = {
  /** NORAD-идентификатор КА. */
  noradId: number;
  /** Идентификатор объекта (цели) из запроса. */
  objectId: string;
  /** Момент видимости (локальное время, ISO без зоны). */
  time: string;
  /** Номер витка. */
  revolution: number;
  /** Крен (gamma), град. */
  gamma: number;
  /** Угол Солнца, град. */
  sunAngle: number;
  /** Наклонная дальность. */
  range: number;
  /** Направление витка. */
  revSign: "ASC" | "DESC";
};

export type PointVisibilityFilters = {
  /** Минимальный угол Солнца, град. */
  sunAngleMin?: number;
  /** Минимальный крен, град. */
  rollMin?: number;
  /** Максимальный крен, град. */
  rollMax?: number;
};

export type GeoPointTarget = {
  id?: string;
  lat: number;
  lon: number;
  height?: number;
};

/**
 * Параметры видимости точки на заданном интервале времени из pcp-ballistics-service
 * (POST /api/obj-view/mpl-point). Возвращает по одному моменту видимости на виток.
 */
export async function fetchPointVisibility(
  noradId: number,
  target: GeoPointTarget,
  fromMs: number,
  toMs: number,
  filters: PointVisibilityFilters = {}
): Promise<PointVisibilityParam[]> {
  const body = {
    satellites: [noradId],
    timeStart: toLocalDateTime(fromMs),
    timeStop: toLocalDateTime(toMs),
    obj: {
      id: target.id ?? "",
      position: {
        lat: target.lat,
        long: target.lon,
        height: target.height ?? 0
      }
    },
    sunAngleMin: filters.sunAngleMin ?? null,
    rollMin: filters.rollMin ?? null,
    rollMax: filters.rollMax ?? null
  };

  let response: Response;
  try {
    response = await fetch(`${BASE}/api/obj-view/mpl-point`, {
      method: "POST",
      headers: { Accept: "application/json", "Content-Type": "application/json" },
      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()) {
    return [];
  }

  return JSON.parse(text) as PointVisibilityParam[];
}

/** Целеуказание (момент/угол места/азимут/дальность) границы зоны радиовидимости. */
export type RvaTargetPosition = {
  /** Момент (локальное время, ISO без зоны). */
  time: string;
  /** Угол места, град. */
  elevation: number;
  /** Азимут, град. */
  azimuth: number;
  /** Наклонная дальность. */
  range: number;
};

/** Зона радиовидимости (ЗРВ) станции для КА на витке. */
export type RvaZone = {
  /** NORAD-идентификатор КА. */
  noradId: number;
  /** Номер станции приёма (совпадает с number из /api/stations). */
  stationId: number;
  /** Номер витка. */
  revolution: number;
  /** Вход в зону. */
  onStart: RvaTargetPosition;
  /** Максимум (кульминация). */
  onMaximum: RvaTargetPosition;
  /** Выход из зоны. */
  onStop: RvaTargetPosition;
  /** Длительность зоны, секунды. */
  duration: number;
};

/**
 * Зоны радиовидимости (ЗРВ) для КА на заданном интервале из pcp-ballistics-service
 * (GET /api/satellites/{norad}/rva). Баллистика считает зоны по реальным станциям приёма
 * (каталог берёт у сервиса станций); каждая зона помечена номером станции (stationId).
 */
export async function fetchSatelliteRva(
  noradId: number,
  fromMs: number,
  toMs: number
): Promise<RvaZone[]> {
  const params = new URLSearchParams({
    time_start: toLocalDateTime(fromMs),
    time_stop: toLocalDateTime(toMs)
  });
  const url = `${BASE}/api/satellites/${noradId}/rva?${params.toString()}`;

  let response: Response;
  try {
    response = await fetch(url, { 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 RvaZone[];
}

/** LocalDateTime без зоны: YYYY-MM-DDTHH:mm:ss. */
function toLocalDateTime(ms: number): string {
  return new Date(ms).toISOString().slice(0, 19);
}

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;
}
