/**
 * Lane B (Paint) public surface. Integration (game.ts) imports from here.
 */
import * as THREE from 'three'
import type { PaintColor, World } from '../contracts'
import { PaintSkin } from './skin'

export { PaintSkin } from './skin'
export type { PaintSkinOptions } from './skin'
export { PaintCannon, solveBallisticVelocity } from './cannon'
export type { PaintCannonConfig } from './cannon'
export { BuffSystem } from './buffs'
export type { BuffTarget } from './buffs'
export { PaintHUD } from './hud'
export {
  COLOR_ORDER,
  colorIndex,
  countBuckets,
  coverageReportFromCounts,
  computeModifiers,
  buffStrength,
  superColor,
  dominantColor,
  ACTIVATE,
  SUPER,
} from './coverage-math'

export interface PaintEventTarget {
  /** The paintable body — its world position is used for proximity gating. */
  mesh: THREE.Object3D
  paint: PaintSkin
}

/**
 * Wire the inbound paint protocol from Lane C onto a blob's skin:
 *   'paint:request-splat'   {point, color, radius}  — bucket dumps, sprays
 *   'paint:request-cleanse' {fraction}              — bubble arches, rinses
 * request-splat is proximity-gated to the blob (ground decals are V1), and a
 * matched splat re-emits 'paint:splatted' {target:'blob'} so downstream listeners
 * (VFX, audio, netcode) see a single canonical splat event. Returns an unsub fn.
 */
export function installPaint(world: World, target: PaintEventTarget): () => void {
  const center = new THREE.Vector3()
  const scale = new THREE.Vector3()

  const worldRadius = (): number => {
    target.mesh.getWorldScale(scale)
    return target.paint.boundingRadius * Math.max(scale.x, scale.y, scale.z)
  }

  const offSplat = world.events.on(
    'paint:request-splat',
    (p: { point: THREE.Vector3; color: PaintColor; radius: number }) => {
      if (!p?.point) return
      target.mesh.getWorldPosition(center)
      if (center.distanceTo(p.point) <= worldRadius() + p.radius) {
        target.paint.splatAtPoint(p.point, p.color, p.radius)
        world.events.emit('paint:splatted', { color: p.color, target: 'blob' })
      }
    },
  )

  const offCleanse = world.events.on(
    'paint:request-cleanse',
    (p: { fraction: number }) => {
      target.paint.cleanse(p?.fraction ?? 1)
    },
  )

  return () => {
    offSplat()
    offCleanse()
  }
}
