import { describe, it, expect, vi, beforeEach } from 'vitest'
import { createHitlCancelByMetadataTool } from '../approval'
import { ToolingError } from '../../types'
import { getToolServices } from '../../registry'
import { createMockExecutionContext } from '../../../test-utils/mocks'

vi.mock('../../registry', () => ({
  getToolServices: vi.fn()
}))

const mockContext = createMockExecutionContext({
  organizationId: 'org-123',
  executionId: 'exec-456',
  resourceId: 'agent-789',
  resourceType: 'agent'
})

const mockCommandQueue = {
  createTask: vi.fn(),
  deleteByMetadata: vi.fn()
}

beforeEach(() => {
  vi.clearAllMocks()
  vi.mocked(getToolServices).mockReturnValue({
    commandQueueService: mockCommandQueue,
    taskSchedulerService: null,
    notificationsService: null,
    emailService: null,
    credentialsService: null,
    integrationService: null,
    leadService: null,
    storageService: null,
    pdfService: null
  })
})

describe('createHitlCancelByMetadataTool', () => {
  it('creates tool with correct properties', () => {
    const tool = createHitlCancelByMetadataTool()
    expect(tool.name).toBe('hitl_cancel_by_metadata')
    expect(tool.execute).toBeInstanceOf(Function)
  })

  it('calls deleteByMetadata with correct params', async () => {
    mockCommandQueue.deleteByMetadata.mockResolvedValue({ deleted: 2 })

    const tool = createHitlCancelByMetadataTool()
    const result = await tool.execute({
      input: { metadata: { contactEmail: 'user@example.com' }, status: 'pending' },
      executionContext: mockContext
    })

    expect(mockCommandQueue.deleteByMetadata).toHaveBeenCalledWith(
      'org-123',
      { contactEmail: 'user@example.com' },
      'pending'
    )
    expect(result).toEqual({ deleted: 2 })
  })

  it('throws when executionContext missing', async () => {
    const tool = createHitlCancelByMetadataTool()
    await expect(tool.execute({ input: { metadata: {} } })).rejects.toThrow('ExecutionContext is unavailable')
  })

  it('throws ToolingError when service unavailable', async () => {
    vi.mocked(getToolServices).mockReturnValue({
      commandQueueService: null,
      taskSchedulerService: null,
      notificationsService: null,
      emailService: null,
      credentialsService: null,
      integrationService: null,
      leadService: null,
      storageService: null,
      pdfService: null
    })

    const tool = createHitlCancelByMetadataTool()
    try {
      await tool.execute({ input: { metadata: {} }, executionContext: mockContext })
      expect.fail('Should have thrown')
    } catch (error) {
      expect(error).toBeInstanceOf(ToolingError)
      expect((error as ToolingError).errorType).toBe('service_unavailable')
    }
  })

  it('propagates errors from service', async () => {
    mockCommandQueue.deleteByMetadata.mockRejectedValue(new Error('DB error'))
    const tool = createHitlCancelByMetadataTool()
    await expect(
      tool.execute({ input: { metadata: {} }, executionContext: mockContext })
    ).rejects.toThrow('DB error')
  })
})
