import { krigingInterpolation, confidenceFromNearestDrill } from './kriging-idw';
import { calculateBlendTwo } from './blending';
import { gradeBand, isWaste, isJvAutoSwitch } from './grade-rules';
import { detectDilution } from './dilution';
import { estimateProfitTzs, findBlocksForTargetProfit, getMarketFromEnv } from './reverse-economics';
import { worldToGrid } from './grid';

describe('module-b grid', () => {
  it('snaps to block grid', () => {
    const g = worldToGrid(12.3, 45.6, -8.2, 5);
    expect(g.grid_i).toBe(2);
    expect(g.block_x).toBe(10);
  });
});

describe('module-b kriging IDW', () => {
  const pts = [
    { x: 0, y: 0, z: 0, ppm: 2 },
    { x: 10, y: 0, z: 0, ppm: 8 },
  ];
  it('interpolates midpoint', () => {
    const p = krigingInterpolation(pts, 5, 0, 0);
    expect(p).toBeGreaterThan(2);
    expect(p).toBeLessThan(8);
  });
  it('returns exact ppm on drill point', () => {
    expect(krigingInterpolation(pts, 0, 0, 0)).toBe(2);
  });
  it('confidence reflects distance', () => {
    const c = confidenceFromNearestDrill(pts, 5, 0, 0, 5);
    expect(c).toBeGreaterThan(0);
    expect(c).toBeLessThanOrEqual(100);
  });
});

describe('module-b blending', () => {
  it('hits target ppm', () => {
    const r = calculateBlendTwo({ tons: 0, ppm: 8 }, { tons: 0, ppm: 2 }, 1000, 4.5);
    expect(r.source1_tons + r.source2_tons).toBeCloseTo(1000, 5);
    expect(r.result_ppm).toBeCloseTo(4.5, 5);
  });
});

describe('module-b grade rules', () => {
  it('classifies bands', () => {
    expect(gradeBand(0.3)).toBe('WASTE');
    expect(isWaste(0.3)).toBe(true);
    expect(isJvAutoSwitch(1.0)).toBe(true);
    expect(gradeBand(3)).toBe('PREMIUM');
  });
});

describe('module-b dilution', () => {
  it('flags sharp drop', () => {
    const prior = [{ ppm: 5 }, { ppm: 5.2 }, { ppm: 4.9 }, { ppm: 5.1 }, { ppm: 5 }];
    expect(detectDilution(prior, 2)).toBe(true);
  });
  it('no flag on stable', () => {
    const prior = [{ ppm: 5 }, { ppm: 5.1 }];
    expect(detectDilution(prior, 4.9)).toBe(false);
  });
});

describe('module-b reverse economics', () => {
  it('profit scales with tons and ppm', () => {
    const m = getMarketFromEnv();
    const p1 = estimateProfitTzs(100, 4, m, {
      processingCostPerTonTzs: 75000,
      transportPerTonTzs: 0,
      chemicalsPerTonTzs: 0,
      recovery: 1,
    });
    const p2 = estimateProfitTzs(200, 4, m, {
      processingCostPerTonTzs: 75000,
      transportPerTonTzs: 0,
      chemicalsPerTonTzs: 0,
      recovery: 1,
    });
    expect(p2).toBeGreaterThan(p1);
  });
  it('finds block for target', () => {
    const candidates = [
      { block_x: 0, block_y: 0, block_z: 0, tons: 100, ppm: 3 },
      { block_x: 1, block_y: 0, block_z: 0, tons: 100, ppm: 6 },
    ];
    const r = findBlocksForTargetProfit(candidates, -1e15, getMarketFromEnv(), {
      processingCostPerTonTzs: 75000,
      transportPerTonTzs: 0,
      chemicalsPerTonTzs: 0,
      recovery: 0.9,
    });
    expect(r).not.toBeNull();
    expect(candidates.some((c) => c.ppm === r!.best.ppm && c.block_x === r!.best.block_x)).toBe(true);
  });
});
