import {
  TguApiError,
  type TguPlan,
  type TguPlanDecision,
  type TguPlanDecisionMessage,
  type TguPlatform
} from "../model/tguTypes";

export type FlightLinePoint = {
  time: string;
  revolution: number;
  lat: number;
  long: number;
  latLeft: number;
  longLeft: number;
  latInnerLeft: number;
  longInnerLeft: number;
  latInnerRight: number;
  longInnerRight: number;
  latRight: number;
  longRight: number;
  revSign: "ASC" | "DESC";
};

export async function fetchFlightLine(
  noradId: string,
  fromMs: number,
  toMs: number
): Promise<FlightLinePoint[]> {
  const toLocalDT = (ms: number) => new Date(ms).toISOString().slice(0, 19);
  const query = new URLSearchParams({
    time_start: toLocalDT(fromMs),
    time_stop: toLocalDT(toMs)
  });
  return fetchJson<FlightLinePoint[]>(
    `/api/tgu-planning/spacecraft/${encodeURIComponent(noradId)}/flight-line?${query}`
  );
}

export async function fetchPlatforms(): Promise<TguPlatform[]> {
  return fetchJson<TguPlatform[]>("/api/tgu-planning/platforms");
}

export async function fetchPlans(historyDays: number, spacecraftId?: string): Promise<TguPlan[]> {
  const query = new URLSearchParams({ historyDays: String(historyDays) });
  const path = spacecraftId
    ? `/api/tgu-planning/spacecraft/${encodeURIComponent(spacecraftId)}/plans?${query}`
    : `/api/tgu-planning/plans?${query}`;

  return fetchJson<TguPlan[]>(path);
}

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>(
    `/api/tgu-planning/plans/${encodeURIComponent(planId)}/decision?${query}`,
    { method: "POST" },
    true
  );
}

async function fetchJson<T>(url: string, init?: RequestInit, decisionRequest = false): Promise<T> {
  let response: Response;
  try {
    response = await fetch(url, {
      headers: { Accept: "application/json" },
      ...init
    });
  } catch (error) {
    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;
}
