-- Executable smoke test for the public LuaCoolProp API documented in the
-- developer reference. Run through scripts/build-examples.sh so the same
-- external CoolProp library is used by Lua and all three TeX formats.

local lcp = require("luacoolprop")

local _, loaded_from = lcp.load_library()
assert(type(loaded_from) == "string", "CoolProp loader name must be a string")
assert(type(lcp.version()) == "string", "CoolProp version must be a string")
assert(type(lcp.gitrevision()) == "string", "CoolProp revision must be a string")
assert(type(lcp.fluid_param_string("R134a", "aliases")) == "string",
  "fluid aliases must be a string")
assert(type(lcp.parameter_information_string("Hmass")) == "string",
  "parameter information must be a string")

local h = lcp.propsSI("Hmass", "P", 2.5e5, "Q", 1, "R134a")
assert(type(h) == "number", "propsSI must return a number")

-- Keep a single deterministic cleanup point around the native handle. The
-- finalizer is a fallback, not the normal resource-management mechanism.
local state
local ok, result = xpcall(function()
  state = lcp.AbstractState("HEOS", "R134a")
  state:update("PT_INPUTS", 3e5, 293.15)
  return state:keyed_output("Hmass")
end, debug.traceback)

if state ~= nil then
  state:free()
  state:free() -- The documented cleanup operation is idempotent.
  state = nil
end

if not ok then
  error(result, 0)
end
assert(type(result) == "number", "AbstractState output must be a number")

local ph = lcp.diagram.get_type("PH")
local curve_options = {
  fluid = "R134a",
  pressure_min = 1e5,
  pressure_max = 2e6,
  enthalpy_scale = 1e-3,
  pressure_scale = 1e-5,
}

local isotherm_points = ph.isotherm_curve(curve_options, 293.15)
assert(#isotherm_points >= 2, "isotherm must contain at least two points")

local quality_points = ph.quality_curve(curve_options, 0.5)
assert(#quality_points >= 2, "quality curve must contain at least two points")

local plot_code = ph.plots({
  fluid = "R134a",
  quality = true,
  isotherm = true,
  quality_values = "0,0.5,1",
  temperature_values = "-20,0,20",
  temperature_unit = "celsius",
  labels = true,
})
assert(plot_code:find("\\addplot", 1, true),
  "PH plot renderer must emit PGFPlots commands")

local process_points, metadata = ph.process_points({
  fluid = "R134a",
  type = "isentropic",
  from = "pressure=2bar,quality=1",
  to = "pressure=10bar",
})
assert(#process_points >= 2, "process must contain at least two points")
assert(metadata.kind == "isentropic", "process kind must be normalized")
assert(type(metadata.to.h) == "number", "completed endpoint must contain enthalpy")

local pv = lcp.diagram.get_type("PV")
local pv_options = {
  fluid = "R134a",
  pressure_min = 1e5,
  pressure_max = 2e6,
  specific_volume_scale = 1,
  pressure_scale = 1e-5,
}
local pv_isotherm = pv.isotherm_curve(pv_options, 293.15)
assert(#pv_isotherm >= 2 and pv_isotherm[1].x > 0,
  "PV isotherm must contain positive log-axis points")
local pv_code = pv.plots({
  fluid = "R134a", quality = true, isotherm = true,
  quality_values = "0,0.5,1", temperature_values = "0,20",
})
assert(pv_code:find("name path=lcp-pv", 1, true),
  "PV renderer must emit diagram-specific named paths")
local pv_process, pv_metadata = pv.process_points({
  fluid = "R134a", type = "isentropic",
  from = "pressure=2bar,quality=1", to = "pressure=10bar",
})
assert(#pv_process >= 2 and pv_metadata.to.x == pv_metadata.to.v,
  "PV process coordinates must expose scaled specific volume")

local ts = lcp.diagram.get_type("TS")
local ts_options = {
  fluid = "R134a",
  pressure_min = 1e5,
  pressure_max = 2e6,
  entropy_scale = 1e-3,
  temperature_scale = 1,
}
local ts_isenthalp = ts.isenthalp_curve(ts_options, 300e3)
assert(#ts_isenthalp >= 2
    and ts_isenthalp[1].x == ts_isenthalp[1].s * 1e-3
    and ts_isenthalp[1].y == ts_isenthalp[1].T,
  "TS isenthalp must expose scaled entropy and temperature")
local ts_code = ts.plots({
  fluid = "R134a", quality = true, isenthalp = true,
  quality_values = "0,0.5,1", enthalpy_values = "250,300,350",
})
assert(ts_code:find("name path=lcp-ts", 1, true),
  "TS renderer must emit diagram-specific named paths")
local ts_process, ts_metadata = ts.process_points({
  fluid = "R134a", type = "isentropic",
  from = "pressure=2bar,quality=1", to = "pressure=10bar",
})
assert(#ts_process == 2 and ts_metadata.from.x == ts_metadata.to.x,
  "TS isentropic process must be an exact vertical segment")

local hs = lcp.diagram.get_type("HS")
local hs_options = {
  fluid = "Water",
  pressure_min = 1e4,
  pressure_max = 3e7,
  entropy_scale = 1e-3,
  enthalpy_scale = 1e-3,
  temperature_unit = "celsius",
  isobar_temperature_min = 10,
  isobar_temperature_max = 500,
}
local hs_isobar = hs.isobar_curve(hs_options, 1e5)
assert(#hs_isobar >= 2
    and hs_isobar[1].x == hs_isobar[1].s * 1e-3
    and hs_isobar[1].y == hs_isobar[1].h * 1e-3,
  "HS isobar must expose scaled entropy and enthalpy")
local hs_code = hs.plots({
  fluid = "Water", quality = true, isochore = true,
  isotherm = true, isobar = true,
  quality_values = "0,0.5,1",
  specific_volume_values = "0.01,0.1,1",
  temperature_values = "100,200,300",
  isobar_values = "0.1,1,10",
})
for _, family in ipairs({"q", "v", "T", "p"}) do
  assert(hs_code:find("name path=lcp-hs-" .. family, 1, true),
    "HS renderer must emit the " .. family .. " family")
end
local hs_process, hs_metadata = hs.process_points({
  fluid = "Water", type = "isentropic",
  from = "pressure=1bar,quality=1", to = "pressure=10bar",
})
assert(#hs_process == 2 and hs_metadata.from.x == hs_metadata.to.x,
  "HS isentropic process must be an exact vertical segment")

local pt = lcp.diagram.get_type("PT")
local pt_constants = lcp.fluid_constants("R134a")
local pt_options = {
  fluid = "R134a", pressure_min = pt_constants.ptriple,
  pressure_max = pt_constants.pcrit * 1.1,
  temperature_axis_unit = "celsius", pressure_axis_unit = "bar",
}
local phase_envelope = pt.phase_envelope_curve(pt_options)
assert(#phase_envelope >= 3 and phase_envelope[1].triple
    and phase_envelope[#phase_envelope].critical,
  "PT phase envelope must join the exact triple and critical points")
local pt_code = pt.plots({
  fluid = "R134a", phase_envelope = true, isentrope = true,
  isenthalp = true, isochore = true,
  entropy_values = "1.4,1.7,2.0",
  enthalpy_values = "200,300,400",
  specific_volume_values = "0.001,0.01,0.1",
})
for _, family in ipairs({"phase-envelope", "s", "h", "v"}) do
  assert(pt_code:find("name path=lcp-pt-" .. family, 1, true),
    "PT renderer must emit the " .. family .. " family")
end
local pt_process, pt_metadata = pt.process_points({
  fluid = "R134a", type = "isentropic",
  from = "pressure=2bar,quality=1", to = "pressure=10bar",
})
assert(#pt_process >= 2 and pt_metadata.diagram_type == "PT",
  "PT process must use the shared process API")

io.write("Lua API smoke test passed\n")
