"""Entropyk — Simple Refrigeration Cycle Example.

This example demonstrates how to use the Python bindings to build and
(eventually) solve a simple vapor-compression refrigeration cycle:

    Compressor → Condenser → Expansion Valve → Evaporator → (loop)

Usage:
    python examples/simple_cycle.py
"""

import entropyk

# ── Step 1: Create physical components ──────────────────────────────────

print("=" * 60)
print("  Entropyk — Simple Refrigeration Cycle")
print("=" * 60)

# Compressor with AHRI 540 coefficients (using defaults)
compressor = entropyk.Compressor(
    speed_rpm=2900.0,
    displacement=0.0001,
    efficiency=0.85,
    fluid="R134a",
)
print(f"\n  {compressor}")

# Condenser coil: UA = 5 kW/K
condenser = entropyk.Condenser(ua=5000.0)
print(f"  {condenser}")

# Thermostatic expansion valve
expansion_valve = entropyk.ExpansionValve(fluid="R134a", opening=0.8)
print(f"  {expansion_valve}")

# Evaporator coil: UA = 3 kW/K
evaporator = entropyk.Evaporator(ua=3000.0)
print(f"  {evaporator}")

# ── Step 2: Build the system graph ──────────────────────────────────────

print("\n---")
print("  Building system graph...")

system = entropyk.System()

# Add components — returns node indices
comp_idx = system.add_component(compressor)
cond_idx = system.add_component(condenser)
exv_idx = system.add_component(expansion_valve)
evap_idx = system.add_component(evaporator)

# Connect them in a cycle
system.add_edge(comp_idx, cond_idx)   # Compressor → Condenser
system.add_edge(cond_idx, exv_idx)    # Condenser → EXV
system.add_edge(exv_idx, evap_idx)    # EXV → Evaporator
system.add_edge(evap_idx, comp_idx)   # Evaporator → Compressor (loop)

print(f"  {system}")

# ── Step 3: Finalize the system ─────────────────────────────────────────

print("  Finalizing system topology...")
system.finalize()
print(f"  State vector length: {system.state_vector_len}")

# ── Step 4: Configure solver ────────────────────────────────────────────

print("\n---")
print("  Configuring solver...")

# Newton-Raphson solver with line search
newton = entropyk.NewtonConfig(
    max_iterations=200,
    tolerance=1e-6,
    line_search=True,
    timeout_ms=10000,
)
print(f"  {newton}")

# Picard solver for backup
picard = entropyk.PicardConfig(
    max_iterations=500,
    tolerance=1e-4,
    relaxation=0.5,
)
print(f"  {picard}")

# Fallback: try Newton first, fall back to Picard
fallback = entropyk.FallbackConfig(newton=newton, picard=picard)
print(f"  {fallback}")

# ── Step 5: Solve ───────────────────────────────────────────────────────

print("\n---")
print("  Solving... (requires real component implementations)")
print("  NOTE: SimpleAdapter placeholders will produce trivial solutions.")

try:
    result = fallback.solve(system)
    print(f"\n  ✅ Solution found!")
    print(f"     Status: {result.status}")
    print(f"     Iterations: {result.iterations}")
    print(f"     Residual: {result.final_residual:.2e}")
    print(f"     State vector ({len(result.state_vector)} vars): "
          f"{result.state_vector[:6]}...")
except entropyk.SolverError as e:
    print(f"\n  ❌ Solver error: {e}")
except entropyk.EntropykError as e:
    print(f"\n  ❌ Entropyk error: {e}")

# ── Working with physical types ─────────────────────────────────────────

print("\n---")
print("  Physical types demo:")

p = entropyk.Pressure(bar=12.0)
print(f"  {p}")
print(f"    = {p.to_pascals():.0f} Pa")
print(f"    = {p.to_kpa():.1f} kPa")
print(f"    = {p.to_bar():.2f} bar")
print(f"    float(p) = {float(p)}")

t = entropyk.Temperature(celsius=45.0)
print(f"  {t}")
print(f"    = {t.to_kelvin():.2f} K")
print(f"    = {t.to_celsius():.2f} °C")
print(f"    = {t.to_fahrenheit():.2f} °F")

h = entropyk.Enthalpy(kj_per_kg=420.0)
print(f"  {h}")
print(f"    = {h.to_j_per_kg():.0f} J/kg")
print(f"    = {h.to_kj_per_kg():.1f} kJ/kg")

m = entropyk.MassFlow(kg_per_s=0.05)
print(f"  {m}")
print(f"    = {m.to_kg_per_s():.3f} kg/s")
print(f"    = {m.to_g_per_s():.1f} g/s")

# Arithmetic
p1 = entropyk.Pressure(bar=10.0)
p2 = entropyk.Pressure(bar=2.0)
print(f"\n  Arithmetic: {p1} + {p2} = {p1 + p2}")
print(f"              {p1} - {p2} = {p1 - p2}")

print("\n" + "=" * 60)
print("  Done!")
print("=" * 60)
