import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { renderHook, waitFor } from '@testing-library/react'
import { http, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
import React from 'react'
import { MessagePlugin } from 'tdesign-react'
import { useStartupSettings, useSaveStartupSettings } from '@/hooks/useSettings'
import type { StartupSettings } from '@/types'

vi.mock('tdesign-react', () => ({
  MessagePlugin: {
    success: vi.fn(),
    error: vi.fn(),
  },
}))

const mockDesktopSettings: StartupSettings = {
  mode: 'desktop',
  editable: true,
  configPath: '/home/user/.nex/config.yaml',
  restartRequired: true,
  config: {
    server: { port: 9826, readTimeout: '30s', writeTimeout: '30s' },
    database: {
      driver: 'sqlite',
      path: '/home/user/.nex/config.db',
      host: '',
      port: 3306,
      user: '',
      password: '',
      dbname: 'nex',
      maxIdleConns: 10,
      maxOpenConns: 100,
      connMaxLifetime: '1h',
    },
    log: { level: 'info', path: '/home/user/.nex/log', maxSize: 100, maxBackups: 10, maxAge: 30, compress: true },
  },
}

const handlers = [
  http.get('/api/settings/startup', () => {
    return HttpResponse.json(mockDesktopSettings)
  }),
  http.put('/api/settings/startup', async ({ request }) => {
    const body = (await request.json()) as Record<string, unknown>
    return HttpResponse.json({
      ...mockDesktopSettings,
      config: (body as Record<string, unknown>).config,
    })
  }),
]

const server = setupServer(...handlers)
beforeAll(() => server.listen({ onUnhandledRequest: 'bypass' }))
afterEach(() => server.resetHandlers())
afterAll(() => server.close())

function createWrapper() {
  const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } })
  return ({ children }: { children: React.ReactNode }) => (
    <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
  )
}

describe('useStartupSettings', () => {
  it('fetches startup settings', async () => {
    const { result } = renderHook(() => useStartupSettings(), { wrapper: createWrapper() })

    await waitFor(() => expect(result.current.isSuccess).toBe(true))
    expect(result.current.data?.mode).toBe('desktop')
    expect(result.current.data?.editable).toBe(true)
    expect(result.current.data?.configPath).toBe('/home/user/.nex/config.yaml')
    expect(result.current.data?.restartRequired).toBe(true)
    expect(result.current.data?.config.server.port).toBe(9826)
    expect(result.current.data?.config.database.driver).toBe('sqlite')
    expect(result.current.data?.config.log.level).toBe('info')
  })
})

describe('useSaveStartupSettings', () => {
  it('saves settings and shows success message for desktop', async () => {
    const { result } = renderHook(() => useSaveStartupSettings(), { wrapper: createWrapper() })

    result.current.mutate({ config: mockDesktopSettings.config })

    await waitFor(() => expect(result.current.isSuccess).toBe(true))
    expect(MessagePlugin.success).toHaveBeenCalledWith(
      '配置已保存到配置文件。当前运行中的服务仍使用启动时配置，重启 Desktop 后生效'
    )
  })

  it('shows error message on failure', async () => {
    server.use(
      http.put('/api/settings/startup', () => {
        return HttpResponse.json({ error: '保存失败' }, { status: 500 })
      })
    )

    const { result } = renderHook(() => useSaveStartupSettings(), { wrapper: createWrapper() })

    result.current.mutate({ config: mockDesktopSettings.config })

    await waitFor(() => expect(result.current.isError).toBe(true))
    expect(MessagePlugin.error).toHaveBeenCalled()
  })
})
