/**
 * Spread rheology. The whole difficulty curve of this game lives in these numbers.
 *
 * The central tension: you need PRESSURE to make a stiff spread flow, but pressure
 * comes from tilting the knife steeper — and past `SCRAPE_ANGLE` a steep knife stops
 * spreading and starts scraping. So cold butter can want more pressure than you are
 * physically allowed to apply without flipping into scrape mode. The way out isn't a
 * better technique, it's warmer toast: don't dawdle in the drawer.
 */

export type SpreadId = 'butter' | 'peanut' | 'mitey';
export type AmountClass = 'thin' | 'normal' | 'thick';

export interface SpreadDef {
  id: SpreadId;
  name: string;
  blurb: string;
  color: [number, number, number];
  gloss: number;
  /** Thickness at which the film fully hides the toast underneath. */
  opaqueAt: number;
  /** Surface relief strength. */
  bump: number;

  /** Pressure needed to make it flow, before any warming. */
  baseYield: number;
  /** How much heat (soft butter + hot toast) reduces that. */
  tempSoftening: number;
  /** 0 self-levels instantly, 1 stays exactly where you put it. */
  viscosity: number;
  /** How much the knife picks up per dip. */
  pickup: number;
  /** How fast it leaves the knife once it IS flowing. */
  transferRate: number;
  /** How much the spread resists the knife (drag on the cursor). */
  drag: number;
  /** How readily it comes back off when you scrape. */
  scrapeEase: number;

  amounts: Record<AmountClass, [number, number]>;
}

export const SPREADS: Record<SpreadId, SpreadDef> = {
  butter: {
    id: 'butter',
    name: 'Butter',
    blurb: 'Straightforward — as long as something in this scene is warm.',
    color: [0.97, 0.72, 0.19],
    gloss: 0.85,
    opaqueAt: 0.5,
    bump: 0.10,
    baseYield: 0.72,
    tempSoftening: 0.78,
    viscosity: 0.72,
    pickup: 0.55,
    transferRate: 1.5,
    drag: 0.5,
    scrapeEase: 1.0,
    amounts: { thin: [0.1, 0.22], normal: [0.25, 0.5], thick: [0.55, 0.9] },
  },
  peanut: {
    id: 'peanut',
    name: 'Peanut Butter',
    blurb: 'Goes on thick, drags like wet sand, never evens itself out.',
    color: [0.64, 0.41, 0.18],
    gloss: 0.3,
    opaqueAt: 0.16,
    bump: 0.28,
    baseYield: 0.38,
    tempSoftening: 0.3,
    viscosity: 0.96,
    pickup: 0.95,
    transferRate: 2.2,
    drag: 1.0,
    scrapeEase: 0.75,
    amounts: { thin: [0.18, 0.32], normal: [0.38, 0.68], thick: [0.75, 1.1] },
  },
  mitey: {
    id: 'mitey',
    name: 'MITEY',
    blurb: 'Spreads like nothing. The skill is taking almost all of it back off.',
    color: [0.14, 0.08, 0.05],
    gloss: 0.62,
    opaqueAt: 0.26,
    bump: 0.03,
    baseYield: 0.14,
    tempSoftening: 0.5,
    viscosity: 0.34,
    pickup: 0.5,
    transferRate: 2.6,
    drag: 0.25,
    scrapeEase: 1.25,
    amounts: { thin: [0.03, 0.11], normal: [0.14, 0.28], thick: [0.32, 0.6] },
  },
};

/** Knife angle past which contact narrows enough to scrape instead of spread. */
export const SCRAPE_ANGLE = 0.62;

/** Angle (0 flat .. 1 on-edge) -> contact pressure. */
export function pressureFromAngle(angle: number): number {
  return 0.1 + 0.9 * Math.pow(Math.max(0, Math.min(1, angle)), 1.3);
}

/** Angle -> contact patch radius in UV units. Flat knife = wide, steep = a line. */
export function contactRadius(angle: number): number {
  return 0.115 - 0.078 * Math.max(0, Math.min(1, angle));
}

/**
 * What it actually takes to make this spread flow right now. Butter on a cold
 * slice with fridge-hard butter is the worst case in the game, by design.
 */
export function effectiveYield(def: SpreadDef, softness: number, toastWarmth: number): number {
  const heat = Math.min(1, softness * 0.55 + toastWarmth * 0.65);
  return def.baseYield * (1 - def.tempSoftening * heat);
}

export function amountClassOf(def: SpreadDef, mean: number): AmountClass | 'none' | 'obscene' {
  if (mean < def.amounts.thin[0] * 0.5) return 'none';
  if (mean <= def.amounts.thin[1]) return 'thin';
  if (mean <= def.amounts.normal[1]) return 'normal';
  if (mean <= def.amounts.thick[1]) return 'thick';
  return 'obscene';
}
