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

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

/** Способ построения окна маршрута относительно момента видимости. */
export type SurveyRouteAnchor = "CENTERED" | "FORWARD";

export type BuildSurveyRouteParams = {
  /** Идентификатор КА (NORAD — тот же, что в obj-view/mpl-point). */
  satelliteId: number;
  /** Момент видимости (локальное время, ISO без зоны). */
  time: string;
  /** Длительность съёмки, секунды. */
  durationSeconds: number;
  /** Крен (gamma), градусы. */
  roll: number;
  /** Угол захвата (полуширина полосы), градусы. */
  captureAngle: number;
  /** Номер витка (0 — определить по орбитальным точкам). */
  revolution?: number;
  /** Способ построения окна относительно момента видимости. */
  anchor?: SurveyRouteAnchor;
  /**
   * Начало интервала плана (локальное время, ISO без зоны). Передаётся при сохранении,
   * чтобы при автосоздании миссии/плана задать корректное окно (для пересечений/наложений).
   */
  planStart?: string;
  /** Конец интервала плана (локальное время, ISO без зоны). См. planStart. */
  planEnd?: string;
};

export type SurveyRoute = {
  satelliteId: number;
  /** Начало съёмки (локальное время, ISO без зоны). */
  timeStart: string;
  /** Длительность съёмки, секунды. */
  duration: number;
  revolution: number;
  /** Крен (gamma), градусы. */
  roll: number;
  /** Угол захвата, градусы. */
  captureAngle: number;
  /** Широта центра контура, градусы. */
  lat: number;
  /** Долгота центра контура, градусы. */
  longitude: number;
  /** Контур полосы съёмки, WKT POLYGON (lon lat, ...). */
  contourWkt: string;
  /** Идентификатор сохранённого режима съёмки в БД (есть только после сохранения). */
  surveyModeId?: number;
};

/**
 * Построение одного маршрута съёмки по параметрам видимости точки без сохранения
 * (pcp-mission-planing-service, POST /api/missions/survey-route/build). Live-превью.
 */
export async function buildSurveyRoute(params: BuildSurveyRouteParams): Promise<SurveyRoute> {
  return postSurveyRoute(`${BASE}/api/missions/survey-route/build`, params);
}

/**
 * Построение и сохранение маршрута съёмки в БД по идентификатору выбранного плана
 * (pcp-mission-planing-service, POST /api/missions/{planId}/survey-route).
 * planId — идентификатор выбранного плана в pcp-tgu-service (= mission_id).
 */
export async function saveSurveyRoute(planId: string, params: BuildSurveyRouteParams): Promise<SurveyRoute> {
  return postSurveyRoute(`${BASE}/api/missions/${encodeURIComponent(planId)}/survey-route`, params);
}

export type SaveDropRouteParams = {
  /** Идентификатор КА (NORAD). */
  satelliteId: number;
  /** Идентификатор/номер станции приёма (из ЗРВ). */
  station: string;
  /** Номер витка зоны радиовидимости. */
  revolution: number;
  /** Начало зоны (локальное время, ISO без зоны). */
  zoneStart: string;
  /** Конец зоны (локальное время, ISO без зоны). */
  zoneStop: string;
  /** Идентификаторы режимов съёмки (survey_modes), сбрасываемых в этой зоне. */
  surveyModeIds: number[];
  /** Начало интервала плана (для автосоздания миссии/плана). */
  planStart?: string;
  /** Конец интервала плана. */
  planEnd?: string;
};

/** Сохранённый режим сброса (ответ /drop-route). */
export type DropMode = {
  id: number;
  planId: number;
  timeStart: string | null;
  revolution: number;
  type: "DROP";
  station: string | null;
  duration: number;
  surveys: number[];
};

/**
 * Ручное добавление сброса по выбранной зоне радиовидимости
 * (pcp-mission-planing-service, POST /api/missions/{planId}/drop-route).
 * planId — идентификатор выбранного плана в pcp-tgu-service (= mission_id).
 */
export async function saveDropRoute(planId: string, params: SaveDropRouteParams): Promise<DropMode> {
  const body = {
    satelliteId: params.satelliteId,
    station: params.station,
    revolution: params.revolution,
    zoneStart: params.zoneStart,
    zoneStop: params.zoneStop,
    surveyModeIds: params.surveyModeIds,
    ...(params.planStart ? { planStart: params.planStart } : {}),
    ...(params.planEnd ? { planEnd: params.planEnd } : {})
  };

  const url = `${BASE}/api/missions/${encodeURIComponent(planId)}/drop-route`;
  let response: Response;
  try {
    response = await fetch(url, {
      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()) {
    throw new TguApiError("Сервис планирования миссий вернул пустой ответ.", "http", response.status);
  }

  return JSON.parse(text) as DropMode;
}

async function postSurveyRoute(url: string, params: BuildSurveyRouteParams): Promise<SurveyRoute> {
  const body = {
    satelliteId: params.satelliteId,
    time: params.time,
    durationSeconds: params.durationSeconds,
    roll: params.roll,
    captureAngle: params.captureAngle,
    revolution: params.revolution ?? 0,
    anchor: params.anchor ?? "CENTERED",
    ...(params.planStart ? { planStart: params.planStart } : {}),
    ...(params.planEnd ? { planEnd: params.planEnd } : {})
  };

  let response: Response;
  try {
    response = await fetch(url, {
      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()) {
    throw new TguApiError("Сервис планирования миссий вернул пустой ответ.", "http", response.status);
  }

  return JSON.parse(text) as SurveyRoute;
}

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