/**
 * Unit tests for src/services/UsageService.ts
 */

import { Pool } from 'pg';
import { UsageService } from '../../../src/services/UsageService';

jest.mock('pg');

const MockPool = Pool as jest.MockedClass<typeof Pool>;

function makePool(): jest.Mocked<Pool> {
  const pool = new MockPool() as jest.Mocked<Pool>;
  pool.query = jest.fn();
  return pool;
}

const TENANT_ID = 'org-abc-123';
const DATE = '2026-04-07';

describe('UsageService', () => {
  let service: UsageService;
  let pool: jest.Mocked<Pool>;

  beforeEach(() => {
    jest.clearAllMocks();
    pool = makePool();
    service = new UsageService(pool);
  });

  describe('getDailyUsage()', () => {
    it('should return usage summary with real api call count', async () => {
      pool.query = jest.fn()
        .mockResolvedValueOnce({ rows: [{ count: '42' }], rowCount: 1 })
        .mockResolvedValueOnce({ rows: [{ count: '5' }], rowCount: 1 });

      const result = await service.getDailyUsage(TENANT_ID, DATE);

      expect(result.tenantId).toBe(TENANT_ID);
      expect(result.date).toBe(DATE);
      expect(result.apiCalls).toBe(42);
      expect(result.agentCount).toBe(5);
    });

    it('should default apiCalls to 0 when no usage row exists', async () => {
      pool.query = jest.fn()
        .mockResolvedValueOnce({ rows: [{ count: '0' }], rowCount: 1 })
        .mockResolvedValueOnce({ rows: [{ count: '3' }], rowCount: 1 });

      const result = await service.getDailyUsage(TENANT_ID, DATE);

      expect(result.apiCalls).toBe(0);
    });

    it('should handle missing count row gracefully (defaults to 0)', async () => {
      pool.query = jest.fn()
        .mockResolvedValueOnce({ rows: [], rowCount: 0 })
        .mockResolvedValueOnce({ rows: [{ count: '2' }], rowCount: 1 });

      const result = await service.getDailyUsage(TENANT_ID, DATE);

      expect(result.apiCalls).toBe(0);
    });

    it('should query usage_events with correct tenant and date params', async () => {
      pool.query = jest.fn()
        .mockResolvedValueOnce({ rows: [{ count: '10' }], rowCount: 1 })
        .mockResolvedValueOnce({ rows: [{ count: '0' }], rowCount: 1 });

      await service.getDailyUsage(TENANT_ID, DATE);

      expect(pool.query).toHaveBeenNthCalledWith(
        1,
        expect.stringContaining('usage_events'),
        [TENANT_ID, DATE],
      );
    });
  });

  describe('getActiveAgentCount()', () => {
    it('should return the count of non-decommissioned agents', async () => {
      pool.query = jest.fn().mockResolvedValue({ rows: [{ count: '7' }], rowCount: 1 });

      const count = await service.getActiveAgentCount(TENANT_ID);

      expect(count).toBe(7);
    });

    it('should return 0 when no agents exist for tenant', async () => {
      pool.query = jest.fn().mockResolvedValue({ rows: [{ count: '0' }], rowCount: 1 });

      const count = await service.getActiveAgentCount(TENANT_ID);

      expect(count).toBe(0);
    });

    it('should exclude decommissioned agents (query contains status check)', async () => {
      pool.query = jest.fn().mockResolvedValue({ rows: [{ count: '3' }], rowCount: 1 });

      await service.getActiveAgentCount(TENANT_ID);

      expect(pool.query).toHaveBeenCalledWith(
        expect.stringContaining('decommissioned'),
        [TENANT_ID],
      );
    });

    it('should handle missing count row gracefully', async () => {
      pool.query = jest.fn().mockResolvedValue({ rows: [], rowCount: 0 });

      const count = await service.getActiveAgentCount(TENANT_ID);

      expect(count).toBe(0);
    });
  });
});
