import { describe, expect, it } from "vitest";
import type { Edge, Node } from "@xyflow/react";
import type { EntropykNodeData } from "./configBuilder";
import { buildDofCoach } from "./dofCoach";
import { hxFamily, hxGlyphKey } from "./hxFamily";

function node(
  id: string,
  type: string,
  params: EntropykNodeData["params"] = {},
): Node<EntropykNodeData> {
  return {
    id,
    type: "entropyk",
    position: { x: 0, y: 0 },
    data: { type, name: id, circuit: 1, params },
  };
}

describe("hxFamily", () => {
  it("distinguishes DX / flooded / plate / coil / MCHX", () => {
    expect(hxFamily("Evaporator")?.badge).toBe("Tubes");
    expect(hxFamily("FloodedEvaporator")?.badge).toBe("Noyé");
    expect(hxFamily("BphxCondenser")?.badge).toBe("Plaques");
    expect(hxFamily("AirCooledCondenser")?.badge).toBe("Coil");
    expect(hxFamily("MchxCondenser")?.badge).toBe("MCHX");
    expect(hxFamily("Condenser")?.badge).toBe("Tubes");
    expect(hxGlyphKey("FloodedEvaporator")).toBe("hx_flooded");
    expect(hxGlyphKey("BphxEvaporator")).toBe("hx_plate");
  });

  it("picks coil vs shell from secondary fluid on Condenser/Evaporator", () => {
    expect(hxGlyphKey("Condenser", { secondaryFluid: "Air" })).toBe("hx_coil");
    expect(hxGlyphKey("Condenser", { secondaryFluid: "Water" })).toBe("hx_shell_cond");
    expect(hxGlyphKey("Evaporator", { secondaryFluid: "Water" })).toBe("hx_shell_evap");
    expect(hxGlyphKey("Evaporator", { secondaryFluid: "Air" })).toBe("hx_dx");
    expect(hxFamily("Condenser", { secondaryFluid: "Air" })?.badge).toBe("Coil");
    expect(hxFamily("Evaporator", { secondaryFluid: "Water" })?.badge).toBe("Tubes");
  });
});

describe("buildDofCoach", () => {
  it("guides empty canvas", () => {
    const coach = buildDofCoach([], []);
    expect(coach.balance).toBe("empty");
    expect(coach.tips[0]?.id).toBe("empty");
  });

  it("flags Fixed P + Fixed ṁ on MassFlowSource-style brine source", () => {
    const nodes = [
      node("src", "BrineSource", {
        p_set_bar: 3,
        t_set_c: 12,
        m_flow_kg_s: 1.2,
        fix_pressure: true,
        fix_mass_flow: true,
      }),
    ];
    const coach = buildDofCoach(nodes, []);
    expect(coach.tips.some((t) => t.id.startsWith("mflow-p"))).toBe(true);
  });

  it("suggests wiring secondary when HX has no secondary edges", () => {
    const nodes = [
      node("comp", "ScrollCompressor", {}),
      node("cond", "Condenser", { ua: 1000 }),
      node("exv", "ExpansionValve", {}),
      node("evap", "Evaporator", { ua: 1000 }),
    ];
    const edges: Edge[] = [];
    const coach = buildDofCoach(nodes, edges);
    expect(coach.tips.some((t) => t.id.startsWith("sec-"))).toBe(true);
  });

  it("handles nodes with undefined type or kind without throwing", () => {
    const nodes: Node<EntropykNodeData>[] = [
      {
        id: "node_1",
        type: "entropyk",
        position: { x: 0, y: 0 },
        data: { name: "test_node", params: {} } as unknown as EntropykNodeData,
      },
    ];
    expect(() => buildDofCoach(nodes, [])).not.toThrow();
  });
});
