import { Test, TestingModule } from '@nestjs/testing';
import { QuotaCheckResult, QuotaGuardService } from './quota-guard.service';
import { EffectiveQuotaService } from './effective-quota.service';
import { PrismaService } from '../../infrastructure/database/prisma.service';

describe('QuotaGuardService', () => {
  let guard: QuotaGuardService;
  let mockQuota: any;

  const allowed: QuotaCheckResult = { allowed:true, quotaType:'quiz_generation', limit:30, used:5, remaining:25, resetAt: null, upgradeAvailable:false };
  const denied: QuotaCheckResult = { allowed:false, quotaType:'quiz_generation', limit:30, used:31, remaining:0, resetAt: null, upgradeAvailable:true };

  beforeEach(async () => {
    mockQuota = {
      reserve: jest.fn(), commit: jest.fn(), release: jest.fn(), setMode: jest.fn(), getMode: jest.fn().mockReturnValue('shadow'), computeEffectiveQuota: jest.fn(),
    };
    const mod: TestingModule = await Test.createTestingModule({
      providers: [QuotaGuardService, { provide: EffectiveQuotaService, useValue: mockQuota }, { provide: PrismaService, useValue: {} }],
    }).compile();
    guard = mod.get(QuotaGuardService);
  });

  it('check calls reserve with correct args', async () => {
    mockQuota.reserve.mockResolvedValue(allowed);
    await guard.check('u1', 'quiz_generation', 'op1');
    expect(mockQuota.reserve).toHaveBeenCalledWith('u1', 'quiz_generation', 'op1', 1);
  });

  it('returns upgradeAvailable=true when denied', async () => {
    mockQuota.reserve.mockResolvedValue(denied);
    const r = await guard.check('u1', 'quiz_generation', 'op1');
    expect(r.allowed).toBe(false);
    expect(r.upgradeAvailable).toBe(true);
    expect(typeof r.resetAt).toBe('string');
  });

  it('buildError returns QUOTA_EXCEEDED for ai types', () => {
    const err = guard.buildError(denied);
    expect(err.errorCode).toBe('QUOTA_EXCEEDED');
    expect(err.upgradeAvailable).toBe(true);
  });

  it('buildError returns STORAGE_LIMIT_EXCEEDED for storage_bytes', () => {
    const err = guard.buildError({ ...denied, quotaType: 'storage_bytes' });
    expect(err.errorCode).toBe('STORAGE_LIMIT_EXCEEDED');
  });

  it('buildError returns KNOWLEDGE_BASE_LIMIT_EXCEEDED', () => {
    const err = guard.buildError({ ...denied, quotaType: 'knowledge_base_count' });
    expect(err.errorCode).toBe('KNOWLEDGE_BASE_LIMIT_EXCEEDED');
  });

  it('buildError returns FILE_SIZE_LIMIT_EXCEEDED', () => {
    const err = guard.buildError({ ...denied, quotaType: 'file_size_bytes' });
    expect(err.errorCode).toBe('FILE_SIZE_LIMIT_EXCEEDED');
  });

  it('confirm delegates to quota service', async () => { await guard.confirm('op1'); expect(mockQuota.commit).toHaveBeenCalledWith('op1'); });
  it('cancel delegates to quota service', async () => { await guard.cancel('op1'); expect(mockQuota.release).toHaveBeenCalledWith('op1'); });
});
