import { describe, it, expect, beforeEach } from 'vitest';
import { GetBudgetStatusUseCase } from '../../../../../../modules/token-accounting/usecases/getBudgetStatus/getBudgetStatus.usecase.js';
import { StubBudgetGateway } from '../../../../../../tests/stubs/budget.stub.js';
import { StubTokenUsageGateway } from '../../../../../../tests/stubs/tokenUsage.stub.js';
import { TokenUsageRecordFactory } from '../../../../../../tests/factories/tokenUsage.factory.js';
import { BUDGET_DEFAULT_USD } from '../../../../../../modules/token-accounting/entities/budget/budgetConfig.schema.js';
describe('GetBudgetStatusUseCase', () => {
    let budgetGateway;
    let tokenUsageGateway;
    let useCase;
    beforeEach(() => {
        budgetGateway = new StubBudgetGateway();
        tokenUsageGateway = new StubTokenUsageGateway();
        useCase = new GetBudgetStatusUseCase({ budgetGateway, tokenUsageGateway });
    });
    it('returns the default 200 limit when the budget gateway has no config persisted', async () => {
        const status = await useCase.execute({
            localPaths: ['/project'],
            now: new Date('2026-05-15T12:00:00Z'),
        });
        expect(status.limitUsd).toBe(BUDGET_DEFAULT_USD);
    });
    it('sums only TokenUsageRecord costs recorded since the start of the current calendar month', async () => {
        await budgetGateway.save({ limitUsd: 200 });
        tokenUsageGateway.setRecords([
            TokenUsageRecordFactory.create({
                recordedAt: '2026-04-29T00:00:00Z',
                usage: { inputTokens: 0, outputTokens: 0, cacheCreationInputTokens: 0, cacheReadInputTokens: 0, costUsd: 999 },
            }),
            TokenUsageRecordFactory.create({
                recordedAt: '2026-05-01T00:00:00Z',
                usage: { inputTokens: 0, outputTokens: 0, cacheCreationInputTokens: 0, cacheReadInputTokens: 0, costUsd: 20 },
            }),
            TokenUsageRecordFactory.create({
                recordedAt: '2026-05-15T00:00:00Z',
                usage: { inputTokens: 0, outputTokens: 0, cacheCreationInputTokens: 0, cacheReadInputTokens: 0, costUsd: 28.5 },
            }),
        ]);
        const status = await useCase.execute({
            localPaths: ['/project'],
            now: new Date('2026-05-20T12:00:00Z'),
        });
        expect(status.consumedUsd).toBeCloseTo(48.5, 2);
    });
    it('computes remainingUsd, percentUsed (2 decimals), exceeded=false when under the limit', async () => {
        await budgetGateway.save({ limitUsd: 200 });
        tokenUsageGateway.setRecords([
            TokenUsageRecordFactory.create({
                recordedAt: '2026-05-10T00:00:00Z',
                usage: { inputTokens: 0, outputTokens: 0, cacheCreationInputTokens: 0, cacheReadInputTokens: 0, costUsd: 48.5 },
            }),
        ]);
        const status = await useCase.execute({
            localPaths: ['/project'],
            now: new Date('2026-05-20T12:00:00Z'),
        });
        expect(status.remainingUsd).toBeCloseTo(151.5, 2);
        expect(status.percentUsed).toBeCloseTo(24.25, 2);
        expect(status.exceeded).toBe(false);
    });
    it('flags exceeded=true and clamps remainingUsd at 0 when consumed >= limit', async () => {
        await budgetGateway.save({ limitUsd: 200 });
        tokenUsageGateway.setRecords([
            TokenUsageRecordFactory.create({
                recordedAt: '2026-05-10T00:00:00Z',
                usage: { inputTokens: 0, outputTokens: 0, cacheCreationInputTokens: 0, cacheReadInputTokens: 0, costUsd: 250 },
            }),
        ]);
        const status = await useCase.execute({
            localPaths: ['/project'],
            now: new Date('2026-05-20T12:00:00Z'),
        });
        expect(status.exceeded).toBe(true);
        expect(status.remainingUsd).toBe(0);
    });
    it('uses the injected now() so a calendar month transition zeroes consumedUsd', async () => {
        await budgetGateway.save({ limitUsd: 200 });
        tokenUsageGateway.setRecords([
            TokenUsageRecordFactory.create({
                recordedAt: '2026-05-31T23:00:00Z',
                usage: { inputTokens: 0, outputTokens: 0, cacheCreationInputTokens: 0, cacheReadInputTokens: 0, costUsd: 200.5 },
            }),
        ]);
        const status = await useCase.execute({
            localPaths: ['/project'],
            now: new Date('2026-06-01T00:00:00Z'),
        });
        expect(status.consumedUsd).toBe(0);
        expect(status.periodStart).toBe('2026-06-01T00:00:00.000Z');
    });
    it('sums consumption across every provided localPath (R2 global)', async () => {
        await budgetGateway.save({ limitUsd: 200 });
        tokenUsageGateway.setRecordsForPath('/repo-a', [
            TokenUsageRecordFactory.create({
                localPath: '/repo-a',
                recordedAt: '2026-05-10T00:00:00Z',
                usage: { inputTokens: 0, outputTokens: 0, cacheCreationInputTokens: 0, cacheReadInputTokens: 0, costUsd: 30 },
            }),
        ]);
        tokenUsageGateway.setRecordsForPath('/repo-b', [
            TokenUsageRecordFactory.create({
                localPath: '/repo-b',
                recordedAt: '2026-05-12T00:00:00Z',
                usage: { inputTokens: 0, outputTokens: 0, cacheCreationInputTokens: 0, cacheReadInputTokens: 0, costUsd: 18.5 },
            }),
        ]);
        const status = await useCase.execute({
            localPaths: ['/repo-a', '/repo-b'],
            now: new Date('2026-05-20T12:00:00Z'),
        });
        expect(status.consumedUsd).toBeCloseTo(48.5, 2);
    });
});
//# sourceMappingURL=getBudgetStatus.usecase.test.js.map