/**
 * Resource Service Tests
 */

import { describe, it, expect, beforeEach, vi } from 'vitest'
import * as resourceService from '../../services/resource'
import { getDb } from '../../db'
import { AppErrors } from '../../lib/errors'
import { Context } from '../../types/context'

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

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

describe('Resource Service', () => {
  let mockDb: { query: ReturnType<typeof vi.fn> }
  let mockContext: Context

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

    mockContext = {
      db: mockDb as never,
      user: {
        id: 'user-1',
        email: 'test@example.com',
        name: 'Test User',
        role: 'USER',
        createdAt: new Date(),
        updatedAt: new Date(),
      },
      tenantContext: {
        tenantId: 'tenant-1',
        isSystemAdmin: false,
      },
    } as Context
  })

  describe('getResource', () => {
    it('should return resource when found', async () => {
      const mockResource = {
        id: 'resource-1',
        name: 'Test Resource',
        type: 'VM',
        status: 'RUNNING',
        site_id: 'site-1',
        tenant_id: 'tenant-1',
        metadata: {},
        created_at: new Date(),
        updated_at: new Date(),
      }

      const mockSite = {
        id: 'site-1',
        name: 'Test Site',
        region: 'us-east-1',
        status: 'ACTIVE',
        metadata: {},
        created_at: new Date(),
        updated_at: new Date(),
      }

      mockDb.query
        .mockResolvedValueOnce({ rows: [mockResource] })
        .mockResolvedValueOnce({ rows: [mockSite] })

      const result = await resourceService.getResource(mockContext, 'resource-1')

      expect(result.id).toBe('resource-1')
      expect(result.name).toBe('Test Resource')
      expect(mockDb.query).toHaveBeenCalledTimes(2)
    })

    it('should throw not found error when resource does not exist', async () => {
      mockDb.query.mockResolvedValueOnce({ rows: [] })

      await expect(resourceService.getResource(mockContext, 'non-existent')).rejects.toThrow()
      await expect(resourceService.getResource(mockContext, 'non-existent')).rejects.toMatchObject({
        code: 'RESOURCE_NOT_FOUND',
      })
    })
  })

  describe('createResource', () => {
    it('should create resource with tenant context', async () => {
      const mockResource = {
        id: 'resource-1',
        name: 'Test Resource',
        type: 'VM',
        status: 'PENDING',
        site_id: 'site-1',
        tenant_id: 'tenant-1',
        metadata: {},
        created_at: new Date(),
        updated_at: new Date(),
      }

      const mockSite = {
        id: 'site-1',
        name: 'Test Site',
        region: 'us-east-1',
        status: 'ACTIVE',
        metadata: {},
        created_at: new Date(),
        updated_at: new Date(),
      }

      // Mock tenant service
      vi.mock('../../services/tenant', () => ({
        tenantService: {
          enforceQuota: vi.fn().mockResolvedValue(undefined),
        },
      }))

      mockDb.query
        .mockResolvedValueOnce({ rows: [mockResource] })
        .mockResolvedValueOnce({ rows: [mockSite] })

      const input = {
        name: 'Test Resource',
        type: 'VM' as const,
        siteId: 'site-1',
        metadata: { cpu: 2, memory: '4Gi' },
      }

      const result = await resourceService.createResource(mockContext, input)

      expect(result.id).toBe('resource-1')
      expect(mockDb.query).toHaveBeenCalled()
    })
  })
})

