/**
 * Tenant Service Tests
 */

import { describe, it, expect, beforeEach, vi } from 'vitest'
import { tenantService } from '../../services/tenant'
import { getDb } from '../../db'

// Mock database
vi.mock('../../db', () => ({
  getDb: vi.fn(),
}))

// Mock logger
vi.mock('../../lib/logger', () => ({
  logger: {
    info: vi.fn(),
    error: vi.fn(),
    warn: vi.fn(),
  },
}))

// Mock identity service
vi.mock('../../services/identity', () => ({
  identityService: {
    createTenantRealm: vi.fn().mockResolvedValue(undefined),
  },
}))

describe('TenantService', () => {
  let mockDb: any

  beforeEach(() => {
    mockDb = {
      query: vi.fn(),
    }
    vi.mocked(getDb).mockReturnValue(mockDb as never)
  })

  describe('createTenant', () => {
    it('should create a tenant with default values', async () => {
      const input = {
        name: 'Test Tenant',
      }

      mockDb.query
        .mockResolvedValueOnce({
          rows: [{
            id: 'tenant-1',
            name: 'Test Tenant',
            domain: null,
            billing_account_id: 'BA-123',
            status: 'PENDING_ACTIVATION',
            tier: 'STANDARD',
            metadata: '{}',
            quota_limits: '{}',
            created_at: new Date(),
            updated_at: new Date(),
          }],
        })
        .mockResolvedValueOnce({ rows: [] })

      const tenant = await tenantService.createTenant(input)

      expect(tenant).toBeDefined()
      expect(tenant.name).toBe('Test Tenant')
      expect(tenant.status).toBe('PENDING_ACTIVATION')
      expect(tenant.tier).toBe('STANDARD')
    })

    it('should create a tenant with custom quotas', async () => {
      const input = {
        name: 'Test Tenant',
        tier: 'ENTERPRISE' as const,
        quotaLimits: {
          compute: {
            vcpu: 16,
            memory: 64,
            instances: 10,
          },
          storage: {
            total: 1000,
          },
        },
      }

      mockDb.query
        .mockResolvedValueOnce({
          rows: [{
            id: 'tenant-1',
            name: 'Test Tenant',
            domain: null,
            billing_account_id: 'BA-123',
            status: 'PENDING_ACTIVATION',
            tier: 'ENTERPRISE',
            metadata: '{}',
            quota_limits: JSON.stringify(input.quotaLimits),
            created_at: new Date(),
            updated_at: new Date(),
          }],
        })
        .mockResolvedValueOnce({ rows: [] })

      const tenant = await tenantService.createTenant(input)

      expect(tenant.tier).toBe('ENTERPRISE')
      expect(tenant.quotaLimits.compute?.vcpu).toBe(16)
    })
  })

  describe('enforceQuota', () => {
    it('should allow resource creation within quota', async () => {
      const tenantId = 'tenant-1'
      const resourceRequest = {
        compute: {
          vcpu: 2,
          memory: 4,
          instances: 1,
        },
      }

      // Mock tenant with quotas
      mockDb.query.mockResolvedValueOnce({
        rows: [{
          quota_limits: JSON.stringify({
            compute: { vcpu: 16, memory: 64, instances: 10 },
          }),
        }],
      })

      // Mock current usage
      mockDb.query.mockResolvedValueOnce({
        rows: [{
          instances: '2',
          vcpu: '4',
          memory: '8',
        }],
      })

      mockDb.query.mockResolvedValueOnce({
        rows: [{ total: '100', per_instance: '50' }],
      })

      mockDb.query.mockResolvedValueOnce({
        rows: [{ bandwidth: '1000', egress: '500' }],
      })

      await expect(
        tenantService.enforceQuota(tenantId, resourceRequest)
      ).resolves.not.toThrow()
    })

    it('should reject resource creation exceeding quota', async () => {
      const tenantId = 'tenant-1'
      const resourceRequest = {
        compute: {
          vcpu: 20, // Exceeds limit of 16
          memory: 4,
          instances: 1,
        },
      }

      // Mock tenant with quotas
      mockDb.query.mockResolvedValueOnce({
        rows: [{
          quota_limits: JSON.stringify({
            compute: { vcpu: 16, memory: 64, instances: 10 },
          }),
        }],
      })

      // Mock current usage
      mockDb.query.mockResolvedValueOnce({
        rows: [{
          instances: '2',
          vcpu: '4',
          memory: '8',
        }],
      })

      mockDb.query.mockResolvedValueOnce({
        rows: [{ total: '100', per_instance: '50' }],
      })

      mockDb.query.mockResolvedValueOnce({
        rows: [{ bandwidth: '1000', egress: '500' }],
      })

      await expect(
        tenantService.enforceQuota(tenantId, resourceRequest)
      ).rejects.toThrow('Quota exceeded')
    })
  })

  describe('getQuotaUsage', () => {
    it('should return current quota usage', async () => {
      const tenantId = 'tenant-1'

      mockDb.query
        .mockResolvedValueOnce({
          rows: [{
            instances: '5',
            vcpu: '10',
            memory: '20',
          }],
        })
        .mockResolvedValueOnce({
          rows: [{
            total: '500',
            per_instance: '100',
          }],
        })
        .mockResolvedValueOnce({
          rows: [{
            bandwidth: '2000',
            egress: '1000',
          }],
        })

      const usage = await tenantService.getQuotaUsage(tenantId)

      expect(usage.compute.instances).toBe(5)
      expect(usage.compute.vcpu).toBe(10)
      expect(usage.compute.memory).toBe(20)
      expect(usage.storage.total).toBe(500)
    })
  })
})

