// Flashlight maths. Pure — the scene turns these numbers into a mask, the AI
// uses them to know whether it's being watched.

import type { WorldPoint } from './venueMap';

export interface ConeSpec {
  x: number; y: number;      // world px, cone apex (the player)
  facing: number;            // radians
  halfAngle: number;         // radians
  range: number;             // world px
}

export const NORMAL_CONE = { halfAngle: 0.55, range: 190 } as const;   // ~63 deg wide
export const UV_CONE     = { halfAngle: 0.42, range: 140 } as const;   // tighter, shorter

const TAU = Math.PI * 2;

/** Shortest signed angular difference a-b, wrapped to (-PI, PI]. */
export function angleDelta(a: number, b: number): number {
  let d = (a - b) % TAU;
  if (d <= -Math.PI) d += TAU;
  else if (d > Math.PI) d -= TAU;
  return d;
}

export function inCone(spec: ConeSpec, x: number, y: number): boolean {
  const dx = x - spec.x;
  const dy = y - spec.y;
  const dist = Math.hypot(dx, dy);
  if (dist > spec.range) return false;
  if (dist === 0) return true; // standing on the torch
  return Math.abs(angleDelta(Math.atan2(dy, dx), spec.facing)) <= spec.halfAngle;
}

/**
 * 0 = invisible, 1 = fully lit. Falls off toward the cone edge AND with distance.
 * Must return 0 outside the cone and >0 strictly inside it.
 */
export function coneVisibility(spec: ConeSpec, x: number, y: number): number {
  const dx = x - spec.x;
  const dy = y - spec.y;
  const dist = Math.hypot(dx, dy);
  if (dist > spec.range) return 0;
  if (dist === 0) return 1;
  const off = Math.abs(angleDelta(Math.atan2(dy, dx), spec.facing));
  if (off > spec.halfAngle) return 0;
  const t = spec.halfAngle === 0 ? 0 : off / spec.halfAngle;
  const d = spec.range === 0 ? 0 : dist / spec.range;
  return (1 - t * t) * (1 - d * d);
}

/** Polygon points (world px) approximating the cone, for a Phaser mask/graphics fill. */
export function conePolygon(spec: ConeSpec, segments = 24): WorldPoint[] {
  const steps = Math.max(1, Math.floor(segments));
  const apex: WorldPoint = { x: spec.x, y: spec.y };
  const pts: WorldPoint[] = [apex];
  const start = spec.facing - spec.halfAngle;
  const span = spec.halfAngle * 2;
  for (let i = 0; i <= steps; i++) {
    const a = start + (span * i) / steps;
    pts.push({ x: spec.x + Math.cos(a) * spec.range, y: spec.y + Math.sin(a) * spec.range });
  }
  pts.push({ ...apex }); // explicit close so callers can stroke it without fixing up
  return pts;
}
