import { describe, expect, it } from "vitest";
import {
  craniumFor,
  HEAD_STYLE_DEFAULTS,
  isDefaultHeadStyle,
  normalizeHeadStyle,
} from "./headStyle.js";

describe("headStyle", () => {
  it("normalizes missing / packed values", () => {
    expect(normalizeHeadStyle(null)).toEqual(HEAD_STYLE_DEFAULTS);
    expect(normalizeHeadStyle({ l: 0.5, j: -0.25, b: 0.1 })).toEqual({
      length: 0.5,
      jaw: -0.25,
      brow: 0.1,
    });
    expect(normalizeHeadStyle({ length: 2, jaw: -3, brow: 9 })).toEqual({
      length: 1,
      jaw: -1,
      brow: 1,
    });
    expect(isDefaultHeadStyle(normalizeHeadStyle({}))).toBe(true);
  });

  it("gives the sexes different faces at neutral sliders", () => {
    const male = craniumFor("male");
    const female = craniumFor("female");

    // The taper is the tell: female cheekbones carry more of the width while
    // the jaw and chin narrow under them.
    expect(female.jawW).toBeLessThan(male.jawW);
    expect(female.chinW).toBeLessThan(male.chinW);
    expect(female.cheekW).toBeGreaterThan(male.cheekW);
    // Softer profile: little brow ridge, a more vertical forehead, smaller nose.
    expect(female.browOut).toBeLessThan(male.browOut);
    expect(female.foreheadSlope).toBeLessThan(male.foreheadSlope);
    expect(female.noseLen).toBeLessThan(male.noseLen);
  });

  it("trades width against length so a long face doesn't just grow", () => {
    const round = craniumFor("male", { length: -1, jaw: 0, brow: 0 });
    const long = craniumFor("male", { length: 1, jaw: 0, brow: 0 });

    expect(long.faceLengthF).toBeGreaterThan(round.faceLengthF);
    expect(long.widthF).toBeLessThan(round.widthF);
  });

  it("squares the lower face on the jaw slider", () => {
    const tapered = craniumFor("male", { length: 0, jaw: -1, brow: 0 });
    const square = craniumFor("male", { length: 0, jaw: 1, brow: 0 });

    expect(square.jawW).toBeGreaterThan(tapered.jawW);
    expect(square.chinW).toBeGreaterThan(tapered.chinW);
  });

  it("flattens the brow ridge to nothing at the soft end", () => {
    const soft = craniumFor("male", { length: 0, jaw: 0, brow: -1 });
    const heavy = craniumFor("male", { length: 0, jaw: 0, brow: 1 });

    expect(heavy.browOut).toBeGreaterThan(soft.browOut);
    expect(heavy.noseOut).toBeGreaterThan(soft.noseOut);
    // Drives the depth of the brow *ring* in the head loft, so it has to stay
    // non-negative — a negative would invert the ring through the skull.
    expect(soft.browOut).toBeLessThan(0.15);
    expect(soft.browOut).toBeGreaterThanOrEqual(0);
  });

  it("keeps the sliders stacked on the sex base, not replacing it", () => {
    const male = craniumFor("male", { length: 0, jaw: 1, brow: 0 });
    const female = craniumFor("female", { length: 0, jaw: 1, brow: 0 });
    // A square-jawed woman still has a narrower jaw than a square-jawed man.
    expect(female.jawW).toBeLessThan(male.jawW);
  });
});
