import { buildCargoTypeTree } from './booking-reference-data.service';
import type { CargoType } from '../rule-engine/entities/cargo-type.entity';

const node = (
  id: string,
  name: string,
  parentGroupId: string | null,
  isActive = true,
): CargoType =>
  ({
    id,
    cargoTypeName: name,
    code: name.toUpperCase().replace(/\s+/g, '_'),
    parentGroupId,
    displayOrder: 0,
    isActive,
    unitOfMeasure: 'PER_TON',
  }) as unknown as CargoType;

describe('buildCargoTypeTree', () => {
  // Bulk ──┬─ Wheat                    (leaf, depth 2)
  //        └─ Steel Billet ──┬─ S1     (leaf, depth 3)
  //                          └─ S2 ─ S2a  (leaf, depth 4)
  const rows = [
    node('bulk', 'Bulk', null),
    node('wheat', 'Wheat', 'bulk'),
    node('steel', 'Steel Billet', 'bulk'),
    node('s1', 'S1', 'steel'),
    node('s2', 'S2', 'steel'),
    node('s2a', 'S2a', 's2'),
    node('general', 'General Cargo', null),
  ];

  it('offers only leaves as commodities, at any depth', () => {
    const [bulk] = buildCargoTypeTree(rows);

    // Leaves stay grouped under their branch (siblings ordered by
    // displayOrder then code — STEEL_BILLET before WHEAT here).
    expect(bulk.children?.map((c) => c.id)).toEqual(['s1', 's2a', 'wheat']);
    // "Steel Billet" is a container for finer types, never bookable itself.
    expect(bulk.children?.some((c) => c.id === 'steel')).toBe(false);
  });

  it('labels deep leaves with their path below the group', () => {
    const [bulk] = buildCargoTypeTree(rows);
    const byId = new Map(bulk.children?.map((c) => [c.id, c.name]));

    expect(byId.get('wheat')).toBe('Wheat');
    expect(byId.get('s1')).toBe('Steel Billet → S1');
    expect(byId.get('s2a')).toBe('Steel Billet → S2 → S2a');
  });

  it('emits a childless group as its own commodity', () => {
    const general = buildCargoTypeTree(rows).find((g) => g.id === 'general');

    expect(general?.children).toEqual([
      expect.objectContaining({ id: 'general', name: 'General Cargo' }),
    ]);
  });

  it('skips inactive nodes and their descendants', () => {
    const withRetired = [
      ...rows,
      node('retired', 'Retired', 'bulk', false),
      node('retiredKid', 'Retired Kid', 'retired', false),
    ];
    const [bulk] = buildCargoTypeTree(withRetired);

    expect(bulk.children?.map((c) => c.id)).not.toContain('retired');
    expect(bulk.children?.map((c) => c.id)).not.toContain('retiredKid');
  });
});
