import { describe, it, expect } from 'vitest';
import { stepEndedToUsage } from '../opencode-usage.js';

describe('stepEndedToUsage (U.6)', () => {
  it('folds cache read+write into input and reasoning into output', () => {
    const u = stepEndedToUsage({
      cost: 0.0123,
      tokens: { input: 100, output: 50, reasoning: 20, cache: { read: 10, write: 5 } },
    });
    expect(u).toEqual({ input: 115, output: 70, cost: 0.0123 });
  });

  it('handles a step with no cache and no reasoning', () => {
    const u = stepEndedToUsage({
      cost: 0,
      tokens: { input: 8, output: 4, reasoning: 0, cache: { read: 0, write: 0 } },
    });
    expect(u).toEqual({ input: 8, output: 4, cost: 0 });
  });

  it('is defensive against a missing tokens block', () => {
    const u = stepEndedToUsage({ cost: 0.5 } as never);
    expect(u).toEqual({ input: 0, output: 0, cost: 0.5 });
  });

  it('is defensive against undefined props', () => {
    expect(stepEndedToUsage(undefined)).toEqual({ input: 0, output: 0, cost: 0 });
  });

  it('drops NaN / negative noise to zero rather than poisoning the accumulated total', () => {
    const u = stepEndedToUsage({
      cost: Number.NaN,
      tokens: {
        input: -5,
        output: Number.NaN,
        reasoning: 3,
        cache: { read: Number.POSITIVE_INFINITY, write: 2 },
      },
    });
    // input: (-5→0) + (Inf→0) + 2 = 2; output: (NaN→0) + 3 = 3; cost: NaN→0
    expect(u).toEqual({ input: 2, output: 3, cost: 0 });
  });

  it('rounds fractional token counts', () => {
    const u = stepEndedToUsage({
      cost: 1.5,
      tokens: { input: 10.6, output: 4.4, reasoning: 0, cache: { read: 0, write: 0 } },
    });
    expect(u).toEqual({ input: 11, output: 4, cost: 1.5 });
  });
});
