import assert from 'node:assert/strict';
import test from 'node:test';

import { applyFieldEffectEraserStroke } from './fieldEffectEraser';
import type { EffectInstance } from './types/effects';

const base = { seed: 1, createdAtMs: 0 };
const makeId = (prefix: string) => `${prefix}_new`;

void test('applyFieldEffectEraserStroke: удаляет точки в радиусе кисти', () => {
  const fog: EffectInstance = {
    ...base,
    id: 'f1',
    type: 'fog',
    points: [
      { x: 0.2, y: 0.5, tMs: 0 },
      { x: 0.5, y: 0.5, tMs: 100 },
      { x: 0.8, y: 0.5, tMs: 200 },
    ],
    radiusN: 0.02,
    opacity: 0.5,
    lifetimeMs: null,
  };
  const next = applyFieldEffectEraserStroke([fog], [{ x: 0.5, y: 0.5, tMs: 0 }], 0.05, makeId);
  assert.equal(next.length, 2);
  const left = next[0];
  const right = next[1];
  assert.ok(left);
  assert.ok(right);
  assert.equal(left.type, 'fog');
  assert.equal(right.type, 'fog');
  assert.equal(left.points.length, 1);
  assert.equal(left.points[0]?.x, 0.2);
  assert.equal(right.points.length, 1);
  assert.equal(right.points[0]?.x, 0.8);
});

void test('applyFieldEffectEraserStroke: стирает вдоль сегмента штриха', () => {
  const rain: EffectInstance = {
    ...base,
    id: 'r1',
    type: 'rain',
    points: [
      { x: 0.1, y: 0.5, tMs: 0 },
      { x: 0.3, y: 0.5, tMs: 50 },
      { x: 0.5, y: 0.5, tMs: 100 },
      { x: 0.7, y: 0.5, tMs: 150 },
      { x: 0.9, y: 0.5, tMs: 200 },
    ],
    radiusN: 0.01,
    opacity: 0.6,
    lifetimeMs: null,
  };
  const next = applyFieldEffectEraserStroke(
    [rain],
    [
      { x: 0.25, y: 0.5, tMs: 0 },
      { x: 0.75, y: 0.5, tMs: 50 },
    ],
    0.04,
    makeId,
  );
  assert.equal(next.length, 2);
  const xs = next.flatMap((i) => (i.type === 'rain' ? i.points.map((p) => p.x) : []));
  assert.deepEqual(xs, [0.1, 0.9]);
});

void test('applyFieldEffectEraserStroke: VFX-огонь стирается как полевой эффект', () => {
  const fire: EffectInstance = {
    ...base,
    id: 'fire_vfx',
    type: 'fire',
    points: [
      { x: 0.2, y: 0.5, tMs: 0 },
      { x: 0.5, y: 0.5, tMs: 100 },
    ],
    radiusN: 0.02,
    opacity: 0.8,
    lifetimeMs: null,
  };
  const next = applyFieldEffectEraserStroke([fire], [{ x: 0.5, y: 0.5, tMs: 0 }], 0.05, makeId);
  assert.equal(next.length, 1);
  const kept = next[0];
  assert.equal(kept?.type === 'fire' && kept.points[0]?.x, 0.2);
});

void test('applyFieldEffectEraserStroke: не трогает эффекты действия', () => {
  const fog: EffectInstance = {
    ...base,
    id: 'f1',
    type: 'fog',
    points: [{ x: 0.5, y: 0.5, tMs: 0 }],
    radiusN: 0.05,
    opacity: 1,
    lifetimeMs: null,
  };
  const bolt: EffectInstance = {
    ...base,
    id: 'L1',
    type: 'lightning',
    start: { x: 0.5, y: 0 },
    end: { x: 0.5, y: 0.8 },
    widthN: 0.02,
    intensity: 1,
    lifetimeMs: 500,
  };
  const next = applyFieldEffectEraserStroke([fog, bolt], [{ x: 0.5, y: 0.5, tMs: 0 }], 0.1, makeId);
  assert.equal(next.length, 1);
  assert.equal(next[0]?.id, 'L1');
});

void test('applyFieldEffectEraserStroke: пустой штрих — без изменений', () => {
  const water: EffectInstance = {
    ...base,
    id: 'w1',
    type: 'water',
    points: [{ x: 0.4, y: 0.4, tMs: 0 }],
    radiusN: 0.05,
    opacity: 0.5,
    lifetimeMs: null,
  };
  const next = applyFieldEffectEraserStroke([water], [], 0.05, makeId);
  assert.equal(next.length, 1);
  assert.equal(next[0]?.id, 'w1');
});

void test('applyFieldEffectEraserStroke: types=["fire"] гасит только огонь', () => {
  const fire: EffectInstance = {
    ...base,
    id: 'fire1',
    type: 'fire',
    points: [
      { x: 0.5, y: 0.5, tMs: 0 },
      { x: 0.55, y: 0.5, tMs: 50 },
    ],
    radiusN: 0.03,
    opacity: 1,
    lifetimeMs: null,
  };
  const fog: EffectInstance = {
    ...base,
    id: 'fog1',
    type: 'fog',
    points: [{ x: 0.5, y: 0.5, tMs: 0 }],
    radiusN: 0.03,
    opacity: 0.5,
    lifetimeMs: null,
  };
  const next = applyFieldEffectEraserStroke(
    [fire, fog],
    [{ x: 0.5, y: 0.5, tMs: 0 }],
    0.08,
    makeId,
    ['fire'],
  );
  assert.equal(next.length, 1);
  assert.equal(next[0]?.id, 'fog1');
});

void test('applyFieldEffectEraserStroke: hitMode=brush не гасит издалека', () => {
  const fire: EffectInstance = {
    ...base,
    id: 'fire1',
    type: 'fire',
    points: [{ x: 0.5, y: 0.5, tMs: 0 }],
    radiusN: 0.08,
    opacity: 1,
    lifetimeMs: null,
  };
  // brush ≈ 0.38 * 0.08 ≈ 0.030; dist 0.06 — мимо, dist 0.02 — попадание.
  const far = applyFieldEffectEraserStroke(
    [fire],
    [{ x: 0.5, y: 0.56, tMs: 0 }],
    0.08,
    makeId,
    ['fire'],
    'brush',
  );
  assert.equal(far.length, 1);
  assert.equal(far[0]?.id, 'fire1');

  const near = applyFieldEffectEraserStroke(
    [fire],
    [{ x: 0.5, y: 0.52, tMs: 0 }],
    0.08,
    makeId,
    ['fire'],
    'brush',
  );
  assert.equal(near.length, 0);
});
