type CosmosColor = string | [number, number, number, number];

function parseBoolean(value: string | undefined, fallback: boolean): boolean {
  if (value === undefined) return fallback;
  const normalized = value.trim().toLowerCase();
  if (["1", "true", "yes", "on"].includes(normalized)) return true;
  if (["0", "false", "no", "off"].includes(normalized)) return false;
  return fallback;
}

function parseNumber(value: string | undefined, fallback: number): number {
  if (value === undefined) return fallback;
  const parsed = Number(value);
  return Number.isFinite(parsed) ? parsed : fallback;
}

function parseOptionalNumber(value: string | undefined): number | undefined {
  if (value === undefined) return undefined;
  const trimmed = value.trim();
  if (trimmed.length === 0) return undefined;
  const parsed = Number(trimmed);
  return Number.isFinite(parsed) ? parsed : undefined;
}

function parseOptionalString(value: string | undefined): string | undefined {
  if (value === undefined) return undefined;
  const trimmed = value.trim();
  return trimmed.length > 0 ? trimmed : undefined;
}

function parseNumberList(value: string | undefined, fallback: number[]): number[] {
  return parseOptionalNumberList(value) ?? fallback;
}

function parseOptionalNumberList(value: string | undefined): number[] | undefined {
  const raw = parseOptionalString(value);
  if (!raw) return undefined;
  const normalized = raw.startsWith("[") && raw.endsWith("]") ? raw.slice(1, -1) : raw;
  const parts = normalized
    .split(",")
    .map((entry) => entry.trim())
    .filter((entry) => entry.length > 0);
  if (parts.length === 0) return undefined;
  const parsed = parts.map((entry) => Number(entry));
  return parsed.every((entry) => Number.isFinite(entry)) ? parsed : undefined;
}

function parseColor(value: string | undefined, fallback: CosmosColor): CosmosColor {
  return parseOptionalColor(value) ?? fallback;
}

function parseOptionalColor(value: string | undefined): CosmosColor | undefined {
  const raw = parseOptionalString(value);
  if (!raw) return undefined;
  const rgba = parseOptionalNumberList(raw);
  if (rgba && rgba.length === 4) {
    return [rgba[0], rgba[1], rgba[2], rgba[3]];
  }
  return raw;
}

function parseOptionalSeed(value: string | undefined): number | string | undefined {
  const raw = parseOptionalString(value);
  if (!raw) return undefined;
  const numeric = Number(raw);
  return Number.isFinite(numeric) ? numeric : raw;
}

function toCssColor(color: CosmosColor): string {
  if (typeof color === "string") return color;
  return `rgba(${color[0]}, ${color[1]}, ${color[2]}, ${color[3] / 255})`;
}

export const cosmosRuntimeConfig = {
  enableSimulation: parseBoolean(import.meta.env.VITE_COSMOS_ENABLE_SIMULATION, true),
  debugLayout: parseBoolean(import.meta.env.VITE_COSMOS_DEBUG_LAYOUT, false),
  backgroundColor: parseColor(import.meta.env.VITE_COSMOS_BACKGROUND_COLOR, "#05070a"),
  spaceSize: parseNumber(import.meta.env.VITE_COSMOS_SPACE_SIZE, 4096),
  pointDefaultColor: parseOptionalColor(import.meta.env.VITE_COSMOS_POINT_DEFAULT_COLOR),
  pointGreyoutColor: parseOptionalColor(import.meta.env.VITE_COSMOS_POINT_GREYOUT_COLOR),
  pointGreyoutOpacity: parseOptionalNumber(import.meta.env.VITE_COSMOS_POINT_GREYOUT_OPACITY),
  pointDefaultSize: parseNumber(import.meta.env.VITE_COSMOS_POINT_DEFAULT_SIZE, 4),
  pointOpacity: parseNumber(import.meta.env.VITE_COSMOS_POINT_OPACITY, 1),
  pointSizeScale: parseNumber(import.meta.env.VITE_COSMOS_POINT_SIZE_SCALE, 1),
  hoveredPointCursor: parseOptionalString(import.meta.env.VITE_COSMOS_HOVERED_POINT_CURSOR) ?? "pointer",
  hoveredLinkCursor: parseOptionalString(import.meta.env.VITE_COSMOS_HOVERED_LINK_CURSOR) ?? "pointer",
  renderHoveredPointRing: parseBoolean(
    import.meta.env.VITE_COSMOS_RENDER_HOVERED_POINT_RING,
    true,
  ),
  hoveredPointRingColor: parseColor(
    import.meta.env.VITE_COSMOS_HOVERED_POINT_RING_COLOR,
    "#35d6ff",
  ),
  focusedPointRingColor: parseColor(
    import.meta.env.VITE_COSMOS_FOCUSED_POINT_RING_COLOR,
    "white",
  ),
  renderLinks: parseBoolean(import.meta.env.VITE_COSMOS_RENDER_LINKS, true),
  linkDefaultColor: parseOptionalColor(import.meta.env.VITE_COSMOS_LINK_DEFAULT_COLOR),
  linkOpacity: parseNumber(import.meta.env.VITE_COSMOS_LINK_OPACITY, 1),
  linkGreyoutOpacity: parseNumber(import.meta.env.VITE_COSMOS_LINK_GREYOUT_OPACITY, 0.1),
  linkDefaultWidth: parseNumber(import.meta.env.VITE_COSMOS_LINK_DEFAULT_WIDTH, 1),
  hoveredLinkColor: parseColor(import.meta.env.VITE_COSMOS_HOVERED_LINK_COLOR, "#ffd166"),
  hoveredLinkWidthIncrease: parseNumber(
    import.meta.env.VITE_COSMOS_HOVERED_LINK_WIDTH_INCREASE,
    2.5,
  ),
  linkWidthScale: parseNumber(import.meta.env.VITE_COSMOS_LINK_WIDTH_SCALE, 1),
  scaleLinksOnZoom: parseBoolean(import.meta.env.VITE_COSMOS_SCALE_LINKS_ON_ZOOM, false),
  curvedLinks: parseBoolean(import.meta.env.VITE_COSMOS_CURVED_LINKS, true),
  curvedLinkSegments: parseNumber(import.meta.env.VITE_COSMOS_CURVED_LINK_SEGMENTS, 19),
  curvedLinkWeight: parseNumber(import.meta.env.VITE_COSMOS_CURVED_LINK_WEIGHT, 0.8),
  curvedLinkControlPointDistance: parseNumber(
    import.meta.env.VITE_COSMOS_CURVED_LINK_CONTROL_POINT_DISTANCE,
    0.5,
  ),
  linkDefaultArrows: parseBoolean(import.meta.env.VITE_COSMOS_LINK_DEFAULT_ARROWS, false),
  linkArrowsSizeScale: parseNumber(import.meta.env.VITE_COSMOS_LINK_ARROWS_SIZE_SCALE, 1),
  linkVisibilityDistanceRange: parseNumberList(
    import.meta.env.VITE_COSMOS_LINK_VISIBILITY_DISTANCE_RANGE,
    [50, 150],
  ),
  linkVisibilityMinTransparency: parseNumber(
    import.meta.env.VITE_COSMOS_LINK_VISIBILITY_MIN_TRANSPARENCY,
    0.25,
  ),
  useClassicQuadtree: parseBoolean(import.meta.env.VITE_COSMOS_USE_CLASSIC_QUADTREE, false),
  simulationDecay: parseNumber(import.meta.env.VITE_COSMOS_SIMULATION_DECAY, 5000),
  simulationGravity: parseNumber(import.meta.env.VITE_COSMOS_SIMULATION_GRAVITY, 0),
  simulationCenter: parseNumber(import.meta.env.VITE_COSMOS_SIMULATION_CENTER, 0.05),
  simulationRepulsion: parseNumber(import.meta.env.VITE_COSMOS_SIMULATION_REPULSION, 0.5),
  simulationRepulsionTheta: parseNumber(
    import.meta.env.VITE_COSMOS_SIMULATION_REPULSION_THETA,
    1.15,
  ),
  simulationRepulsionQuadtreeLevels: parseNumber(
    import.meta.env.VITE_COSMOS_SIMULATION_REPULSION_QUADTREE_LEVELS,
    12,
  ),
  simulationLinkSpring: parseNumber(import.meta.env.VITE_COSMOS_SIMULATION_LINK_SPRING, 1),
  simulationLinkDistance: parseNumber(import.meta.env.VITE_COSMOS_SIMULATION_LINK_DISTANCE, 10),
  simulationLinkDistRandomVariationRange: parseNumberList(
    import.meta.env.VITE_COSMOS_SIMULATION_LINK_DISTANCE_RANDOM_VARIATION_RANGE,
    [1, 1.2],
  ),
  simulationRepulsionFromMouse: parseNumber(
    import.meta.env.VITE_COSMOS_SIMULATION_REPULSION_FROM_MOUSE,
    2,
  ),
  enableRightClickRepulsion: parseBoolean(
    import.meta.env.VITE_COSMOS_ENABLE_RIGHT_CLICK_REPULSION,
    false,
  ),
  simulationFriction: parseNumber(import.meta.env.VITE_COSMOS_SIMULATION_FRICTION, 0.1),
  simulationCluster: parseNumber(import.meta.env.VITE_COSMOS_SIMULATION_CLUSTER, 0.1),
  showFPSMonitor: parseBoolean(import.meta.env.VITE_COSMOS_SHOW_FPS_MONITOR, false),
  pixelRatio: parseNumber(import.meta.env.VITE_COSMOS_PIXEL_RATIO, 2),
  scalePointsOnZoom: parseBoolean(import.meta.env.VITE_COSMOS_SCALE_POINTS_ON_ZOOM, false),
  initialZoomLevel: parseOptionalNumber(import.meta.env.VITE_COSMOS_INITIAL_ZOOM_LEVEL),
  enableZoom: parseBoolean(import.meta.env.VITE_COSMOS_ENABLE_ZOOM, true),
  enableSimulationDuringZoom: parseBoolean(
    import.meta.env.VITE_COSMOS_ENABLE_SIMULATION_DURING_ZOOM,
    false,
  ),
  enableDrag: parseBoolean(import.meta.env.VITE_COSMOS_ENABLE_DRAG, true),
  fitViewOnInit: parseBoolean(import.meta.env.VITE_COSMOS_FIT_VIEW_ON_INIT, false),
  fitViewDelay: parseNumber(import.meta.env.VITE_COSMOS_FIT_VIEW_DELAY, 250),
  fitViewPadding: parseNumber(import.meta.env.VITE_COSMOS_FIT_VIEW_PADDING, 0.12),
  fitViewDuration: parseNumber(import.meta.env.VITE_COSMOS_FIT_VIEW_DURATION, 250),
  randomSeed: parseOptionalSeed(import.meta.env.VITE_COSMOS_RANDOM_SEED),
  pointSamplingDistance: parseNumber(
    import.meta.env.VITE_COSMOS_POINT_SAMPLING_DISTANCE,
    150,
  ),
  rescalePositions: parseBoolean(import.meta.env.VITE_COSMOS_RESCALE_POSITIONS, false),
  attribution: parseOptionalString(import.meta.env.VITE_COSMOS_ATTRIBUTION),
};

export const cosmosBackgroundCss = toCssColor(cosmosRuntimeConfig.backgroundColor);
