import type { TriggerEvent } from '@/app/components/plugins/types'
import type { TriggerProviderApiEntity } from '@/app/components/workflow/block-selector/types'
import { fireEvent, render, screen } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { EventDetailDrawer } from '../event-detail-drawer'

vi.mock('@/app/components/header/account-setting/model-provider-page/hooks', () => ({
  useLanguage: () => 'en_US',
}))

vi.mock('@langgenius/dify-ui/cn', () => ({
  cn: (...args: (string | undefined | false | null)[]) => args.filter(Boolean).join(' '),
}))

vi.mock('@/app/components/plugins/card/base/card-icon', () => ({
  default: () => <span data-testid="card-icon" />,
}))

vi.mock('@/app/components/plugins/card/base/description', () => ({
  default: ({ text }: { text: string }) => <div data-testid="description">{text}</div>,
}))

vi.mock('@/app/components/plugins/card/base/org-info', () => ({
  default: ({ orgName }: { orgName: string }) => <div data-testid="org-info">{orgName}</div>,
}))

vi.mock('@/app/components/tools/utils/to-form-schema', () => ({
  triggerEventParametersToFormSchemas: (params: Array<Record<string, unknown>>) =>
    params.map(p => ({
      label: (p.label as Record<string, string>) || { en_US: p.name as string },
      type: (p.type as string) || 'text-input',
      required: (p.required as boolean) || false,
      description: p.description as Record<string, string> | undefined,
    })),
}))

vi.mock('@/app/components/workflow/nodes/_base/components/variable/object-child-tree-panel/show/field', () => ({
  default: ({ name }: { name: string }) => <div data-testid="output-field">{name}</div>,
}))

const mockEventInfo = {
  name: 'test-event',
  identity: {
    author: 'test-author',
    name: 'test-event',
    label: { en_US: 'Test Event' },
  },
  description: { en_US: 'Test event description' },
  parameters: [
    {
      name: 'param1',
      label: { en_US: 'Parameter 1' },
      type: 'text-input',
      auto_generate: null,
      template: null,
      scope: null,
      required: true,
      multiple: false,
      default: null,
      min: null,
      max: null,
      precision: null,
      description: { en_US: 'A test parameter' },
    },
  ],
  output_schema: {
    properties: {
      result: { type: 'string', description: 'Result' },
    },
    required: ['result'],
  },
} as unknown as TriggerEvent

const mockProviderInfo = {
  provider: 'test-provider',
  author: 'test-author',
  name: 'test-provider/test-name',
  icon: 'icon.png',
  description: { en_US: 'Provider desc' },
  supported_creation_methods: [],
} as unknown as TriggerProviderApiEntity

describe('EventDetailDrawer', () => {
  const mockOnClose = vi.fn()

  beforeEach(() => {
    vi.clearAllMocks()
  })

  describe('Rendering', () => {
    it('should render drawer', () => {
      render(<EventDetailDrawer eventInfo={mockEventInfo} providerInfo={mockProviderInfo} onClose={mockOnClose} />)

      expect(screen.getByRole('dialog'))!.toBeInTheDocument()
    })

    it('should render event title', () => {
      render(<EventDetailDrawer eventInfo={mockEventInfo} providerInfo={mockProviderInfo} onClose={mockOnClose} />)

      expect(screen.getByText('Test Event'))!.toBeInTheDocument()
    })

    it('should render event description', () => {
      render(<EventDetailDrawer eventInfo={mockEventInfo} providerInfo={mockProviderInfo} onClose={mockOnClose} />)

      expect(screen.getByTestId('description'))!.toHaveTextContent('Test event description')
    })

    it('should render org info', () => {
      render(<EventDetailDrawer eventInfo={mockEventInfo} providerInfo={mockProviderInfo} onClose={mockOnClose} />)

      expect(screen.getByTestId('org-info'))!.toBeInTheDocument()
    })

    it('should render parameters section', () => {
      render(<EventDetailDrawer eventInfo={mockEventInfo} providerInfo={mockProviderInfo} onClose={mockOnClose} />)

      expect(screen.getByText('tools.setBuiltInTools.parameters'))!.toBeInTheDocument()
      expect(screen.getByText('Parameter 1'))!.toBeInTheDocument()
    })

    it('should render output section', () => {
      render(<EventDetailDrawer eventInfo={mockEventInfo} providerInfo={mockProviderInfo} onClose={mockOnClose} />)

      expect(screen.getByText('pluginTrigger.events.output'))!.toBeInTheDocument()
      expect(screen.getByTestId('output-field'))!.toHaveTextContent('result')
    })

    it('should render back button', () => {
      render(<EventDetailDrawer eventInfo={mockEventInfo} providerInfo={mockProviderInfo} onClose={mockOnClose} />)

      expect(screen.getByText('plugin.detailPanel.operation.back'))!.toBeInTheDocument()
    })
  })

  describe('User Interactions', () => {
    it('should call onClose when close button clicked', () => {
      render(<EventDetailDrawer eventInfo={mockEventInfo} providerInfo={mockProviderInfo} onClose={mockOnClose} />)

      // Find the close button (ActionButton with action-btn class)
      const closeButton = screen.getAllByRole('button').find(btn => btn.classList.contains('action-btn'))
      if (closeButton)
        fireEvent.click(closeButton)

      expect(mockOnClose).toHaveBeenCalledTimes(1)
    })

    it('should call onClose when back clicked', () => {
      render(<EventDetailDrawer eventInfo={mockEventInfo} providerInfo={mockProviderInfo} onClose={mockOnClose} />)

      fireEvent.click(screen.getByText('plugin.detailPanel.operation.back'))

      expect(mockOnClose).toHaveBeenCalledTimes(1)
    })
  })

  describe('Edge Cases', () => {
    it('should handle no parameters', () => {
      const eventWithNoParams = { ...mockEventInfo, parameters: [] }
      render(<EventDetailDrawer eventInfo={eventWithNoParams} providerInfo={mockProviderInfo} onClose={mockOnClose} />)

      expect(screen.getByText('pluginTrigger.events.item.noParameters'))!.toBeInTheDocument()
    })

    it('should handle no output schema', () => {
      const eventWithNoOutput = { ...mockEventInfo, output_schema: {} }
      render(<EventDetailDrawer eventInfo={eventWithNoOutput} providerInfo={mockProviderInfo} onClose={mockOnClose} />)

      expect(screen.getByText('pluginTrigger.events.output'))!.toBeInTheDocument()
      expect(screen.queryByTestId('output-field')).not.toBeInTheDocument()
    })
  })

  describe('Parameter Types', () => {
    it('should display correct type for number-input', () => {
      const eventWithNumber = {
        ...mockEventInfo,
        parameters: [{ ...mockEventInfo.parameters[0]!, type: 'number-input' }],
      }
      render(<EventDetailDrawer eventInfo={eventWithNumber} providerInfo={mockProviderInfo} onClose={mockOnClose} />)

      expect(screen.getByText('tools.setBuiltInTools.number'))!.toBeInTheDocument()
    })

    it('should display correct type for checkbox', () => {
      const eventWithCheckbox = {
        ...mockEventInfo,
        parameters: [{ ...mockEventInfo.parameters[0]!, type: 'checkbox' }],
      }
      render(<EventDetailDrawer eventInfo={eventWithCheckbox} providerInfo={mockProviderInfo} onClose={mockOnClose} />)

      expect(screen.getByText('boolean'))!.toBeInTheDocument()
    })

    it('should display correct type for file', () => {
      const eventWithFile = {
        ...mockEventInfo,
        parameters: [{ ...mockEventInfo.parameters[0]!, type: 'file' }],
      }
      render(<EventDetailDrawer eventInfo={eventWithFile} providerInfo={mockProviderInfo} onClose={mockOnClose} />)

      expect(screen.getByText('tools.setBuiltInTools.file'))!.toBeInTheDocument()
    })

    it('should display original type for unknown types', () => {
      const eventWithUnknown = {
        ...mockEventInfo,
        parameters: [{ ...mockEventInfo.parameters[0]!, type: 'custom-type' }],
      }
      render(<EventDetailDrawer eventInfo={eventWithUnknown} providerInfo={mockProviderInfo} onClose={mockOnClose} />)

      expect(screen.getByText('custom-type'))!.toBeInTheDocument()
    })
  })

  describe('Output Schema Conversion', () => {
    it('should handle array type in output schema', () => {
      const eventWithArrayOutput = {
        ...mockEventInfo,
        output_schema: {
          properties: {
            items: { type: 'array', items: { type: 'string' }, description: 'Array items' },
          },
          required: [],
        },
      }
      render(<EventDetailDrawer eventInfo={eventWithArrayOutput} providerInfo={mockProviderInfo} onClose={mockOnClose} />)

      expect(screen.getByText('pluginTrigger.events.output'))!.toBeInTheDocument()
    })

    it('should handle nested properties in output schema', () => {
      const eventWithNestedOutput = {
        ...mockEventInfo,
        output_schema: {
          properties: {
            nested: {
              type: 'object',
              properties: { inner: { type: 'string' } },
              required: ['inner'],
            },
          },
          required: [],
        },
      }
      render(<EventDetailDrawer eventInfo={eventWithNestedOutput} providerInfo={mockProviderInfo} onClose={mockOnClose} />)

      expect(screen.getByText('pluginTrigger.events.output'))!.toBeInTheDocument()
    })

    it('should handle enum in output schema', () => {
      const eventWithEnumOutput = {
        ...mockEventInfo,
        output_schema: {
          properties: {
            status: { type: 'string', enum: ['active', 'inactive'], description: 'Status' },
          },
          required: [],
        },
      }
      render(<EventDetailDrawer eventInfo={eventWithEnumOutput} providerInfo={mockProviderInfo} onClose={mockOnClose} />)

      expect(screen.getByText('pluginTrigger.events.output'))!.toBeInTheDocument()
    })

    it('should handle array type schema', () => {
      const eventWithArrayType = {
        ...mockEventInfo,
        output_schema: {
          properties: {
            multi: { type: ['string', 'null'], description: 'Multi type' },
          },
          required: [],
        },
      }
      render(<EventDetailDrawer eventInfo={eventWithArrayType} providerInfo={mockProviderInfo} onClose={mockOnClose} />)

      expect(screen.getByText('pluginTrigger.events.output'))!.toBeInTheDocument()
    })
  })
})
