import type { MapProjection } from "../geometry/mapProjection";
import type { GeoPoint } from "../model/mapTypes";

// Слой следа покрытия (вкладка «Слоты»): заливка union контуров выбранных/забронированных слотов.
// Отдельный draw-пасс (D3) — НЕ MapPolygon, не в spatialIndex/hit-тесте. Цвет — violet flat .22
// без обводки (выбран на /plan-design-review: отличим от swath/complexPlan/requests + CVD).
//
// «Flat» (а не additive): все кольца кладём в ОДИН путь и заливаем одним ctx.fill() на проход —
// перекрытия не темнеют (это одна операция заливки при одной opacity). Чтобы перекрывающиеся кольца
// при nonzero-намотке не «вычитались» в дыры, нормализуем ориентацию колец к одному знаку площади.

type Pt = { x: number; y: number };

const FILL = "rgba(167, 139, 219, 0.22)";

function unwrapX(points: Pt[], worldSize: number): Pt[] {
  if (points.length === 0) return [];
  const out: Pt[] = [points[0]!];
  let prevX = points[0]!.x;
  for (let i = 1; i < points.length; i++) {
    let x = points[i]!.x;
    while (x - prevX > worldSize / 2) x -= worldSize;
    while (prevX - x > worldSize / 2) x += worldSize;
    out.push({ x, y: points[i]!.y });
    prevX = x;
  }
  return out;
}

function signedArea(points: Pt[]): number {
  let area = 0;
  for (let i = 0, j = points.length - 1; i < points.length; j = i++) {
    area += (points[j]!.x - points[i]!.x) * (points[j]!.y + points[i]!.y);
  }
  return area;
}

function inView(points: Pt[], dx: number, vw: number, vh: number): boolean {
  return points.some((p) => {
    const x = p.x + dx;
    return x >= -64 && x <= vw + 64 && p.y >= -64 && p.y <= vh + 64;
  });
}

export function drawCoverage(
  ctx: CanvasRenderingContext2D,
  rings: GeoPoint[][],
  projection: MapProjection,
  viewport: { width: number; height: number }
) {
  if (rings.length === 0) return;

  // Готовим экранные кольца с единой ориентацией (CW), чтобы nonzero-заливка объединяла, а не вычитала.
  const screenRings: Pt[][] = [];
  for (const ring of rings) {
    if (ring.length < 3) continue;
    const raw = ring.map((p) => projection.project(p));
    const pts = unwrapX(raw, projection.worldSize);
    if (signedArea(pts) < 0) pts.reverse();
    screenRings.push(pts);
  }
  if (screenRings.length === 0) return;

  ctx.save();
  ctx.fillStyle = FILL;
  // Один путь со всеми кольцами как подпути + одна заливка на сдвиг мира → плоская opacity.
  for (const dx of [0, projection.worldSize, -projection.worldSize]) {
    let any = false;
    ctx.beginPath();
    for (const pts of screenRings) {
      if (!inView(pts, dx, viewport.width, viewport.height)) continue;
      any = true;
      for (let i = 0; i < pts.length; i++) {
        if (i === 0) ctx.moveTo(pts[i]!.x + dx, pts[i]!.y);
        else ctx.lineTo(pts[i]!.x + dx, pts[i]!.y);
      }
      ctx.closePath();
    }
    if (any) ctx.fill("nonzero");
  }
  ctx.restore();
}
