/**
 * Client for the Entropyk REST API (Axum server in demo/).
 *
 * In development, requests go through the Next.js rewrite proxy
 * (/api/entropyk/* → http://localhost:3030/api/* by default; see next.config.mjs).
 */

import type { ComponentMeta } from "./componentMeta";

const API_BASE =
  process.env.NEXT_PUBLIC_API_URL || "/api/entropyk";

export interface IterationInfo {
  iteration: number;
  residual_norm: number;
  delta_norm: number;
  alpha?: number | null;
  max_residual_index?: number | null;
  max_residual?: number;
}

export interface SimulationResult {
  input: string;
  status: "converged" | "failed" | "error" | string;
  convergence?: {
    iterations?: number;
    final_residual?: number;
    tolerance?: number;
    strategy?: string;
    iteration_history?: IterationInfo[];
    converged?: boolean;
    status?: string;
  };
  iterations?: number;
  state?: Array<{
    edge?: number;
    edge_id?: number;
    pressure_bar?: number;
    pressure_pa?: number;
    enthalpy_kj_kg?: number;
    enthalpy_j_kg?: number;
    mass_flow_kg_s?: number;
    source?: string;
    target?: string;
    source_port?: string;
    target_port?: string;
    temperature_c?: number;
    saturation_temperature_c?: number;
  }>;
  performance?: {
    q_cooling_kw?: number | null;
    q_heating_kw?: number | null;
    compressor_power_kw?: number | null;
    cop?: number | null;
    cooling_capacity_w?: number | null;
    heating_capacity_w?: number | null;
    compressor_power_w?: number | null;
    pump_power_w?: number | null;
    cop_cooling?: number | null;
    cop_heating?: number | null;
  };
  components?: Array<{
    name: string;
    component_type: string;
    circuit: number;
    inlet?: { pressure_pa: number; enthalpy_j_kg: number };
    outlet?: { pressure_pa: number; enthalpy_j_kg: number };
    energy?: { heat_transfer_w: number; work_w: number };
  }>;
  error?: string | null;
  failure_diagnostics?: {
    final_residual_norm?: number;
    last_residual_norm?: number;
    dominant_residual_index?: number;
    dominant_residual_value?: number;
  } | null;
  /** Degrees-of-freedom summary after topology finalize (CLI hard gate). */
  dof?: DofSummary | null;
}

/** Degrees-of-freedom summary returned by the CLI after finalize. */
export interface DofSummary {
  n_equations: number;
  n_unknowns: number;
  balance: string;
  summary: string;
}

export interface SimulateResponse {
  ok: boolean;
  result?: SimulationResult;
  error?: string;
}

export interface MollierPoint {
  t_k: number;
  p_bar: number;
  h_liq_kj_kg: number;
  h_vap_kj_kg: number;
}

export interface MollierResponse {
  ok: boolean;
  fluid: string;
  saturation: MollierPoint[];
  error?: string | null;
}

export async function fetchComponents(): Promise<ComponentMeta[]> {
  const res = await fetch(`${API_BASE}/components`, { cache: "no-store" });
  if (!res.ok) throw new Error(`Failed to fetch components: ${res.status}`);
  return res.json();
}

export async function simulate(config: unknown): Promise<SimulateResponse> {
  const healthy = await checkHealth();
  if (!healthy) {
    throw new Error(
      `Entropyk API is down (${API_BASE}/health). Start ui-server: cargo run -p entropyk-demo --bin ui-server`,
    );
  }

  let res: Response;
  try {
    res = await fetch(`${API_BASE}/simulate`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(config),
    });
  } catch (e) {
    const detail = e instanceof Error ? e.message : String(e);
    throw new Error(
      `Cannot reach Entropyk API (${API_BASE}). ui-server may have crashed mid-solve (CoolProp). Restart it on :3030. ${detail}`,
    );
  }
  if (!res.ok) {
    const body = (await res.text().catch(() => "")).trim();
    const hint =
      res.status === 500 || res.status === 502 || res.status === 504
        ? " — ui-server likely crashed (CoolProp race) or was restarting. Restart: cargo run -p entropyk-demo --bin ui-server"
        : "";
    throw new Error(
      `Simulate request failed: ${res.status}${hint}${body ? `\n${body.slice(0, 400)}` : ""}`,
    );
  }
  return res.json();
}

export async function fetchMollier(fluid: string): Promise<MollierResponse> {
  const res = await fetch(`${API_BASE}/mollier?fluid=${encodeURIComponent(fluid)}`, { cache: "no-store" });
  if (!res.ok) throw new Error(`Failed to fetch Mollier data: ${res.status}`);
  return res.json();
}

export async function checkHealth(): Promise<boolean> {
  try {
    const res = await fetch(`${API_BASE}/health`, { cache: "no-store" });
    return res.ok;
  } catch {
    return false;
  }
}
