import { act, renderHook, waitFor } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import { DataType } from '../../types'
import useEditDatasetMetadata from '../use-edit-dataset-metadata'

const mockDoAddMetaData = vi.fn().mockResolvedValue({})
const mockDoRenameMetaData = vi.fn().mockResolvedValue({})
const mockDoDeleteMetaData = vi.fn().mockResolvedValue({})
const mockToggleBuiltInStatus = vi.fn().mockResolvedValue({})

vi.mock('@/service/knowledge/use-metadata', () => ({
  useDatasetMetaData: () => ({
    data: {
      doc_metadata: [
        { id: '1', name: 'field_one', type: DataType.string, count: 5 },
        { id: '2', name: 'field_two', type: DataType.number, count: 3 },
      ],
      built_in_field_enabled: false,
    },
  }),
  useCreateMetaData: () => ({
    mutate: mockDoAddMetaData,
  }),
  useRenameMeta: () => ({
    mutate: mockDoRenameMetaData,
  }),
  useDeleteMetaData: () => ({
    mutateAsync: mockDoDeleteMetaData,
  }),
  useUpdateBuiltInStatus: () => ({
    mutateAsync: mockToggleBuiltInStatus,
  }),
  useBuiltInMetaDataFields: () => ({
    data: {
      fields: [
        { name: 'created_at', type: DataType.time },
        { name: 'modified_at', type: DataType.time },
      ],
    },
  }),
}))

vi.mock('@langgenius/dify-ui/toast', () => ({
  default: {
    notify: vi.fn(),
  },
  toast: {
    success: vi.fn(),
    error: vi.fn(),
    warning: vi.fn(),
    info: vi.fn(),
  },
}))

// Mock useCheckMetadataName
vi.mock('../use-check-metadata-name', () => ({
  default: () => ({
    checkName: (name: string) => ({
      errorMsg: name && /^[a-z][a-z0-9_]*$/.test(name) ? '' : 'Invalid name',
    }),
  }),
}))

// Mock localStorage
const localStorageMock = {
  getItem: vi.fn(),
  setItem: vi.fn(),
  removeItem: vi.fn(),
  clear: vi.fn(),
}
Object.defineProperty(window, 'localStorage', { value: localStorageMock })

describe('useEditDatasetMetadata', () => {
  const defaultProps = {
    datasetId: 'ds-1',
    onUpdateDocList: vi.fn(),
  }

  beforeEach(() => {
    vi.clearAllMocks()
    localStorageMock.getItem.mockReturnValue(null)
  })

  describe('Hook Initialization', () => {
    it('should initialize with isShowEditModal as false', () => {
      const { result } = renderHook(() => useEditDatasetMetadata(defaultProps))
      expect(result.current.isShowEditModal).toBe(false)
    })

    it('should return showEditModal function', () => {
      const { result } = renderHook(() => useEditDatasetMetadata(defaultProps))
      expect(typeof result.current.showEditModal).toBe('function')
    })

    it('should return hideEditModal function', () => {
      const { result } = renderHook(() => useEditDatasetMetadata(defaultProps))
      expect(typeof result.current.hideEditModal).toBe('function')
    })

    it('should return datasetMetaData', () => {
      const { result } = renderHook(() => useEditDatasetMetadata(defaultProps))
      expect(result.current.datasetMetaData).toBeDefined()
    })

    it('should return handleAddMetaData function', () => {
      const { result } = renderHook(() => useEditDatasetMetadata(defaultProps))
      expect(typeof result.current.handleAddMetaData).toBe('function')
    })

    it('should return handleRename function', () => {
      const { result } = renderHook(() => useEditDatasetMetadata(defaultProps))
      expect(typeof result.current.handleRename).toBe('function')
    })

    it('should return handleDeleteMetaData function', () => {
      const { result } = renderHook(() => useEditDatasetMetadata(defaultProps))
      expect(typeof result.current.handleDeleteMetaData).toBe('function')
    })

    it('should return builtInMetaData', () => {
      const { result } = renderHook(() => useEditDatasetMetadata(defaultProps))
      expect(result.current.builtInMetaData).toBeDefined()
    })

    it('should return builtInEnabled', () => {
      const { result } = renderHook(() => useEditDatasetMetadata(defaultProps))
      expect(typeof result.current.builtInEnabled).toBe('boolean')
    })

    it('should return setBuiltInEnabled function', () => {
      const { result } = renderHook(() => useEditDatasetMetadata(defaultProps))
      expect(typeof result.current.setBuiltInEnabled).toBe('function')
    })
  })

  describe('Modal Control', () => {
    it('should show modal when showEditModal is called', () => {
      const { result } = renderHook(() => useEditDatasetMetadata(defaultProps))

      act(() => {
        result.current.showEditModal()
      })

      expect(result.current.isShowEditModal).toBe(true)
    })

    it('should hide modal when hideEditModal is called', () => {
      const { result } = renderHook(() => useEditDatasetMetadata(defaultProps))

      act(() => {
        result.current.showEditModal()
      })

      act(() => {
        result.current.hideEditModal()
      })

      expect(result.current.isShowEditModal).toBe(false)
    })

    it('should handle toggle of modal state', () => {
      const { result } = renderHook(() => useEditDatasetMetadata(defaultProps))

      // Initially closed
      expect(result.current.isShowEditModal).toBe(false)

      // Show, hide, show
      act(() => result.current.showEditModal())
      expect(result.current.isShowEditModal).toBe(true)

      act(() => result.current.hideEditModal())
      expect(result.current.isShowEditModal).toBe(false)

      act(() => result.current.showEditModal())
      expect(result.current.isShowEditModal).toBe(true)
    })
  })

  describe('handleAddMetaData', () => {
    it('should call doAddMetaData with valid name', async () => {
      const { result } = renderHook(() => useEditDatasetMetadata(defaultProps))

      await act(async () => {
        await result.current.handleAddMetaData({
          name: 'valid_name',
          type: DataType.string,
        })
      })

      expect(mockDoAddMetaData).toHaveBeenCalled()
    })

    it('should reject invalid name', async () => {
      const { result } = renderHook(() => useEditDatasetMetadata(defaultProps))

      await expect(
        act(async () => {
          await result.current.handleAddMetaData({
            name: '',
            type: DataType.string,
          })
        }),
      ).rejects.toThrow()
    })
  })

  describe('handleRename', () => {
    it('should call doRenameMetaData with valid name', async () => {
      const { result } = renderHook(() => useEditDatasetMetadata(defaultProps))

      await act(async () => {
        await result.current.handleRename({
          id: '1',
          name: 'new_valid_name',
          type: DataType.string,
          count: 5,
        })
      })

      expect(mockDoRenameMetaData).toHaveBeenCalled()
    })

    it('should call onUpdateDocList after rename', async () => {
      const onUpdateDocList = vi.fn()
      const { result } = renderHook(() =>
        useEditDatasetMetadata({ ...defaultProps, onUpdateDocList }),
      )

      await act(async () => {
        await result.current.handleRename({
          id: '1',
          name: 'renamed',
          type: DataType.string,
          count: 5,
        })
      })

      await waitFor(() => {
        expect(onUpdateDocList).toHaveBeenCalled()
      })
    })

    it('should reject invalid name for rename', async () => {
      const { result } = renderHook(() => useEditDatasetMetadata(defaultProps))

      await expect(
        act(async () => {
          await result.current.handleRename({
            id: '1',
            name: 'Invalid Name',
            type: DataType.string,
            count: 5,
          })
        }),
      ).rejects.toThrow()
    })
  })

  describe('handleDeleteMetaData', () => {
    it('should call doDeleteMetaData', async () => {
      const { result } = renderHook(() => useEditDatasetMetadata(defaultProps))

      await act(async () => {
        await result.current.handleDeleteMetaData('1')
      })

      expect(mockDoDeleteMetaData).toHaveBeenCalledWith('1')
    })

    it('should call onUpdateDocList after delete', async () => {
      const onUpdateDocList = vi.fn()
      const { result } = renderHook(() =>
        useEditDatasetMetadata({ ...defaultProps, onUpdateDocList }),
      )

      await act(async () => {
        await result.current.handleDeleteMetaData('1')
      })

      await waitFor(() => {
        expect(onUpdateDocList).toHaveBeenCalled()
      })
    })
  })

  describe('Built-in Status', () => {
    it('should toggle built-in status', async () => {
      const { result } = renderHook(() => useEditDatasetMetadata(defaultProps))

      await act(async () => {
        await result.current.setBuiltInEnabled(true)
      })

      expect(mockToggleBuiltInStatus).toHaveBeenCalledWith(true)
    })
  })

  describe('Edge Cases', () => {
    it('should handle different datasetIds', () => {
      const { result, rerender } = renderHook(
        props => useEditDatasetMetadata(props),
        { initialProps: defaultProps },
      )

      expect(result.current).toBeDefined()

      rerender({ ...defaultProps, datasetId: 'ds-2' })

      expect(result.current).toBeDefined()
    })
  })
})
