/**
 * FROZEN CONTRACTS — the seams between lanes A (blob/course), B (paint),
 * C (machine). Lanes never edit this file; integration (game.ts) owns changes.
 * Lanes communicate through these types and world.events ONLY.
 */
import type * as THREE from 'three'
import type RAPIER from '@dimforge/rapier3d-compat'

// ---- Paint palette (GDD §6) ------------------------------------------------
export type PaintColor =
  | 'red' | 'orange' | 'yellow' | 'green' | 'blue' | 'purple' | 'pink'

export const PALETTE: Record<PaintColor, string> = {
  red: '#FF3B30',
  orange: '#FF9500',
  yellow: '#FFD60A',
  green: '#34C759',
  blue: '#0A84FF',
  purple: '#AF52DE',
  pink: '#FF6EB4',
}
export const BASE_WHITE = '#F5F5F7'

/** Fractions of TOTAL body surface, 0..1. Unpainted = 1 - total. */
export interface CoverageReport {
  total: number
  byColor: Record<PaintColor, number>
}

// ---- Blob ------------------------------------------------------------------
/** Written by BuffSystem (lane B); read every frame by the controller (lane A). */
export interface BlobModifiers {
  speedMul: number   // 1 = base
  jumpMul: number    // 1 = base
  massMul: number    // 1 = base; paint = weight
  grip: number       // 0..1 extra effective friction
  size: number       // 1 = base uniform scale (visual + collider)
  waterproof: boolean
  glow: number       // 0..1 super-state emissive pulse
}

export const defaultModifiers = (): BlobModifiers => ({
  speedMul: 1, jumpMul: 1, massMul: 1, grip: 0, size: 1,
  waterproof: false, glow: 0,
})

export interface PaintSkin {
  applySplat(uv: THREE.Vector2, color: PaintColor, radius: number): void
  splatAtPoint(worldPoint: THREE.Vector3, color: PaintColor, radius: number): void
  coverage(): CoverageReport
  cleanse(fraction: number): void
}

export interface Blob {
  group: THREE.Group          // root, added to scene
  mesh: THREE.Mesh            // UV-mapped paintable body mesh
  body: RAPIER.RigidBody
  modifiers: BlobModifiers
  paint?: PaintSkin           // attached during integration
}

// ---- Systems / world -------------------------------------------------------
export interface System {
  /** Called at fixed 60Hz, after physics step. */
  update(dt: number): void
}

export type EventHandler = (payload: any) => void
export interface Events {
  on(name: string, fn: EventHandler): () => void
  emit(name: string, payload?: any): void
}

export interface World {
  scene: THREE.Scene
  camera: THREE.PerspectiveCamera
  renderer: THREE.WebGLRenderer
  physics: RAPIER.World
  rapier: typeof RAPIER
  events: Events
  blob?: Blob
  addSystem(s: System): void
  /** Per-render-frame hooks (visual-only work: cameras, jiggle, particles). */
  onFrame(fn: (dt: number) => void): void
  /** Manually advance the fixed-step sim (tests, headless verification). */
  tick(steps?: number): void
  /** Run frame hooks + render one frame (screenshots while backgrounded). */
  renderOnce(): void
  start(): void
}

// ---- Event names (the wire protocol between lanes) -------------------------
// 'machine:signal'         {id: string}
// 'paint:request-splat'    {point: THREE.Vector3, color: PaintColor, radius: number}
// 'paint:request-cleanse'  {fraction: number}
// 'paint:splatted'         {color: PaintColor, target: 'blob'|'world'}
// 'blob:landed'            {impact: number}
// 'blob:jumped'            {}
