import React, { useEffect, useRef } from 'react';

import type {
  SceneDarknessRevealStroke,
  SceneDarknessState,
  SceneDarknessStrokeMode,
} from '../../../shared/types';
import { normalizeSceneDarknessStrokeMode } from '../../../shared/types/sceneDarkness';

export type SceneDarknessOverlayProps = {
  state: SceneDarknessState | null;
  viewport?: { x: number; y: number; w: number; h: number };
  /** 1.0 — полностью чёрный (Presentation); 0.5 — полупрозрачный (Control). */
  overlayAlpha: number;
  style?: React.CSSProperties;
};

function drawDarknessStroke(
  ctx: CanvasRenderingContext2D,
  stroke: SceneDarknessRevealStroke | { points: { x: number; y: number }[]; radiusN: number; mode?: SceneDarknessStrokeMode },
  w: number,
  h: number,
): void {
  const pts = stroke.points;
  if (pts.length === 0) return;
  const mode = normalizeSceneDarknessStrokeMode(stroke.mode);
  ctx.globalCompositeOperation = mode === 'cover' ? 'source-over' : 'destination-out';
  ctx.fillStyle = '#000000';
  ctx.strokeStyle = '#000000';
  const r = stroke.radiusN * Math.min(w, h);
  if (pts.length === 1) {
    const p = pts[0];
    if (!p) return;
    ctx.beginPath();
    ctx.arc(p.x * w, p.y * h, r, 0, Math.PI * 2);
    ctx.fill();
    return;
  }
  ctx.lineCap = 'round';
  ctx.lineJoin = 'round';
  ctx.lineWidth = r * 2;
  ctx.beginPath();
  const first = pts[0];
  if (!first) return;
  ctx.moveTo(first.x * w, first.y * h);
  for (let i = 1; i < pts.length; i++) {
    const p = pts[i];
    if (!p) continue;
    ctx.lineTo(p.x * w, p.y * h);
  }
  ctx.stroke();
}

export function SceneDarknessOverlay({
  state,
  viewport,
  overlayAlpha,
  style,
}: SceneDarknessOverlayProps) {
  const canvasRef = useRef<HTMLCanvasElement | null>(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas || !state?.enabled || !viewport) return;
    const w = Math.max(1, Math.round(viewport.w));
    const h = Math.max(1, Math.round(viewport.h));
    if (canvas.width !== w) canvas.width = w;
    if (canvas.height !== h) canvas.height = h;
    const ctx = canvas.getContext('2d');
    if (!ctx) return;

    ctx.globalCompositeOperation = 'source-over';
    ctx.fillStyle = '#000000';
    ctx.fillRect(0, 0, w, h);

    for (const stroke of state.strokes) {
      drawDarknessStroke(ctx, stroke, w, h);
    }
    if (state.draft && state.draft.points.length > 0) {
      drawDarknessStroke(ctx, state.draft, w, h);
    }
  }, [state, viewport]);

  if (!state?.enabled || !viewport) return null;

  return (
    <canvas
      ref={canvasRef}
      aria-hidden
      style={{
        position: 'absolute',
        left: viewport.x,
        top: viewport.y,
        width: viewport.w,
        height: viewport.h,
        opacity: overlayAlpha,
        pointerEvents: 'none',
        zIndex: 3,
        ...style,
      }}
    />
  );
}
