import React from 'react'
import { render, fireEvent, waitFor } from '@testing-library/react-native'
import MessageScreen from '../message'

// Mock expo-status-bar
jest.mock('expo-status-bar', () => ({
  StatusBar: 'StatusBar',
}))

// Mock react-i18next
jest.mock('react-i18next', () => ({
  useTranslation: () => ({
    t: (key: string) => {
      const translations: Record<string, string> = {
        'message.title': '消息',
        'message.markAllRead': '全部已读',
        'message.noMessages': '暂无消息',
      }
      return translations[key] || key
    },
  }),
}))

// Mock expo-router
const mockPush = jest.fn()
const mockUseFocusEffect = jest.fn((callback: () => void) => {
  // 立即执行 callback 来模拟页面获得焦点
  callback()
})
jest.mock('expo-router', () => ({
  useRouter: () => ({
    push: mockPush,
    replace: jest.fn(),
    back: jest.fn(),
  }),
  useLocalSearchParams: () => ({}),
  useFocusEffect: (callback: () => void) => mockUseFocusEffect(callback),
}))

// Mock hooks
const mockExecute = jest.fn()
const mockLoadMore = jest.fn()
const mockRefetch = jest.fn()
const mockMarkRead = jest.fn()
const mockBatchMarkRead = jest.fn()
const mockDeleteMessage = jest.fn()
const mockAnnouncementExecute = jest.fn()

// Default mock data
const mockMessages = [
  {
    id: '1',
    type: 'ACTIVITY' as const,
    title: '有人点赞了你的作品',
    content: '用户A点赞了你的模板',
    isRead: false,
    createdAt: new Date('2026-01-29T10:00:00'),
    data: { subType: 'TEMPLATE_LIKED', templateId: 'template-1' },
  },
  {
    id: '2',
    type: 'SYSTEM' as const,
    title: '生成成功',
    content: '你的模板已生成完成',
    isRead: true,
    createdAt: new Date('2026-01-28T10:00:00'),
    data: { subType: 'TEMPLATE_GENERATION_SUCCESS', generationId: 'gen-1' },
  },
  {
    id: '3',
    type: 'BILLING' as const,
    title: '积分扣除',
    content: '消耗10积分',
    isRead: false,
    createdAt: new Date('2026-01-27T10:00:00'),
    data: { subType: 'CREDITS_DEDUCTED', credits: 10 },
  },
]

const mockAnnouncements = [
  {
    id: 'ann-1',
    title: '系统公告：新功能上线',
    content: '我们上线了新功能',
    link: 'https://example.com/announcement',
    createdAt: new Date('2026-01-29T08:00:00'),
  },
]

jest.mock('@/hooks/use-messages', () => ({
  useMessages: jest.fn(() => ({
    messages: mockMessages,
    loading: false,
    loadingMore: false,
    refreshing: false,
    error: null,
    execute: mockExecute,
    refetch: mockRefetch,
    loadMore: mockLoadMore,
    hasMore: true,
  })),
}))

jest.mock('@/hooks/use-message-actions', () => ({
  useMessageActions: jest.fn(() => ({
    markRead: mockMarkRead,
    markReadLoading: false,
    markReadError: null,
    batchMarkRead: mockBatchMarkRead,
    batchMarkReadLoading: false,
    batchMarkReadError: null,
    deleteMessage: mockDeleteMessage,
    deleteLoading: false,
    deleteError: null,
  })),
}))

jest.mock('@/hooks/use-announcements', () => ({
  useAnnouncements: jest.fn(() => ({
    announcements: mockAnnouncements,
    loading: false,
    error: null,
    execute: mockAnnouncementExecute,
    refetch: jest.fn(),
    loadMore: jest.fn(),
    hasMore: false,
  })),
}))

jest.mock('@/hooks/use-message-unread-count', () => ({
  useMessageUnreadCount: jest.fn(() => ({
    count: 2,
    loading: false,
    error: null,
    execute: jest.fn(),
  })),
}))

// Mock components
jest.mock('@/components/LoadingState', () => 'LoadingState')
jest.mock('@/components/ErrorState', () => 'ErrorState')
jest.mock('@/components/PaginationLoader', () => 'PaginationLoader')

describe('MessageScreen', () => {
  beforeEach(() => {
    jest.clearAllMocks()
  })

  describe('Page Structure', () => {
    it('should render page header with title "消息"', () => {
      const { getByText } = render(<MessageScreen />)
      expect(getByText('消息')).toBeTruthy()
    })

    it('should render "全部已读" button in header', () => {
      const { getByText } = render(<MessageScreen />)
      expect(getByText('全部已读')).toBeTruthy()
    })

    it('should render MessageTabBar component', () => {
      const { getByTestId } = render(<MessageScreen />)
      expect(getByTestId('tab-all')).toBeTruthy()
      expect(getByTestId('tab-activity')).toBeTruthy()
      expect(getByTestId('tab-system')).toBeTruthy()
      expect(getByTestId('tab-billing')).toBeTruthy()
    })
  })

  describe('Announcement Banner', () => {
    it('should render AnnouncementBanner when announcements exist', () => {
      const { getByTestId } = render(<MessageScreen />)
      expect(getByTestId('announcement-banner')).toBeTruthy()
    })

    it('should not render AnnouncementBanner when no announcements', () => {
      const { useAnnouncements } = require('@/hooks/use-announcements')
      useAnnouncements.mockReturnValue({
        announcements: [],
        loading: false,
        error: null,
        execute: mockAnnouncementExecute,
      })

      const { queryByTestId } = render(<MessageScreen />)
      expect(queryByTestId('announcement-banner')).toBeNull()
    })
  })

  describe('Message List', () => {
    it('should render message list with MessageCard components', () => {
      const { getAllByTestId } = render(<MessageScreen />)
      const messageCards = getAllByTestId('message-card')
      expect(messageCards.length).toBe(3)
    })

    it('should render MessageEmptyState when no messages', () => {
      const { useMessages } = require('@/hooks/use-messages')
      useMessages.mockReturnValue({
        messages: [],
        loading: false,
        loadingMore: false,
        error: null,
        execute: mockExecute,
        refetch: mockRefetch,
        loadMore: mockLoadMore,
        hasMore: false,
      })

      const { getByTestId } = render(<MessageScreen />)
      expect(getByTestId('message-empty-state')).toBeTruthy()
    })

    it('should wrap MessageCard with SwipeToDelete', () => {
      // Reset mock to default with messages
      const { useMessages } = require('@/hooks/use-messages')
      useMessages.mockReturnValue({
        messages: mockMessages,
        loading: false,
        loadingMore: false,
        error: null,
        execute: mockExecute,
        refetch: mockRefetch,
        loadMore: mockLoadMore,
        hasMore: true,
      })

      const { getAllByTestId } = render(<MessageScreen />)
      const swipeContainers = getAllByTestId('swipe-container')
      expect(swipeContainers.length).toBe(3)
    })
  })

  describe('Tab Switching', () => {
    beforeEach(() => {
      // Reset to default mock
      const { useMessages } = require('@/hooks/use-messages')
      useMessages.mockReturnValue({
        messages: mockMessages,
        loading: false,
        loadingMore: false,
        error: null,
        execute: mockExecute,
        refetch: mockRefetch,
        loadMore: mockLoadMore,
        hasMore: true,
      })

      const { useAnnouncements } = require('@/hooks/use-announcements')
      useAnnouncements.mockReturnValue({
        announcements: mockAnnouncements,
        loading: false,
        error: null,
        execute: mockAnnouncementExecute,
      })
    })

    it('should show all messages when "全部" tab is active', () => {
      const { getAllByTestId } = render(<MessageScreen />)
      const messageCards = getAllByTestId('message-card')
      expect(messageCards.length).toBe(3)
    })

    it('should filter ACTIVITY messages when "互动" tab is clicked', async () => {
      const { getByTestId, getAllByTestId } = render(<MessageScreen />)

      fireEvent.press(getByTestId('tab-activity'))

      await waitFor(() => {
        const messageCards = getAllByTestId('message-card')
        expect(messageCards.length).toBe(1)
      })
    })

    it('should filter SYSTEM messages when "系统" tab is clicked', async () => {
      const { getByTestId, getAllByTestId } = render(<MessageScreen />)

      fireEvent.press(getByTestId('tab-system'))

      await waitFor(() => {
        const messageCards = getAllByTestId('message-card')
        expect(messageCards.length).toBe(1)
      })
    })

    it('should filter BILLING messages when "账单" tab is clicked', async () => {
      const { getByTestId, getAllByTestId } = render(<MessageScreen />)

      fireEvent.press(getByTestId('tab-billing'))

      await waitFor(() => {
        const messageCards = getAllByTestId('message-card')
        expect(messageCards.length).toBe(1)
      })
    })

    it('should show empty state when filtered tab has no messages', async () => {
      const { useMessages } = require('@/hooks/use-messages')
      useMessages.mockReturnValue({
        messages: [mockMessages[0]], // Only ACTIVITY message
        loading: false,
        loadingMore: false,
        error: null,
        execute: mockExecute,
        refetch: mockRefetch,
        loadMore: mockLoadMore,
        hasMore: false,
      })

      const { getByTestId, queryByTestId } = render(<MessageScreen />)

      fireEvent.press(getByTestId('tab-billing'))

      await waitFor(() => {
        expect(getByTestId('message-empty-state')).toBeTruthy()
      })
    })
  })

  describe('Mark All Read', () => {
    beforeEach(() => {
      const { useMessages } = require('@/hooks/use-messages')
      useMessages.mockReturnValue({
        messages: mockMessages,
        loading: false,
        loadingMore: false,
        error: null,
        execute: mockExecute,
        refetch: mockRefetch,
        loadMore: mockLoadMore,
        hasMore: true,
      })
    })

    it('should call batchMarkRead with unread message ids when "全部已读" is clicked', async () => {
      const { getByText } = render(<MessageScreen />)

      fireEvent.press(getByText('全部已读'))

      await waitFor(() => {
        expect(mockBatchMarkRead).toHaveBeenCalledWith(['1', '3'])
      })
    })

    it('should only mark unread messages in current tab as read', async () => {
      const { getByText, getByTestId } = render(<MessageScreen />)

      // Switch to ACTIVITY tab
      fireEvent.press(getByTestId('tab-activity'))

      // Click mark all read
      fireEvent.press(getByText('全部已读'))

      await waitFor(() => {
        expect(mockBatchMarkRead).toHaveBeenCalledWith(['1'])
      })
    })

    it('should refetch messages after marking all as read', async () => {
      const { getByText } = render(<MessageScreen />)

      fireEvent.press(getByText('全部已读'))

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

  describe('Swipe to Delete', () => {
    beforeEach(() => {
      const { useMessages } = require('@/hooks/use-messages')
      useMessages.mockReturnValue({
        messages: mockMessages,
        loading: false,
        loadingMore: false,
        error: null,
        execute: mockExecute,
        refetch: mockRefetch,
        loadMore: mockLoadMore,
        hasMore: true,
      })
    })

    it('should call deleteMessage when swipe delete button is pressed', async () => {
      const { getAllByTestId } = render(<MessageScreen />)

      const deleteButtons = getAllByTestId('swipe-delete-button')
      fireEvent.press(deleteButtons[0])

      await waitFor(() => {
        expect(mockDeleteMessage).toHaveBeenCalledWith('1')
      })
    })

    it('should refetch messages after deletion', async () => {
      const { getAllByTestId } = render(<MessageScreen />)

      const deleteButtons = getAllByTestId('swipe-delete-button')
      fireEvent.press(deleteButtons[0])

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

  describe('Message Click Navigation', () => {
    beforeEach(() => {
      const { useMessages } = require('@/hooks/use-messages')
      useMessages.mockReturnValue({
        messages: mockMessages,
        loading: false,
        loadingMore: false,
        error: null,
        execute: mockExecute,
        refetch: mockRefetch,
        loadMore: mockLoadMore,
        hasMore: true,
      })
    })

    it('should navigate to /templateDetail when TEMPLATE_LIKED message is clicked', async () => {
      const { getAllByTestId } = render(<MessageScreen />)

      const messageCards = getAllByTestId('message-card')
      fireEvent.press(messageCards[0])

      await waitFor(() => {
        expect(mockPush).toHaveBeenCalledWith(expect.stringContaining('/templateDetail'))
      })
    })

    it('should navigate to /generationRecord when TEMPLATE_GENERATION_SUCCESS message is clicked', async () => {
      const { getAllByTestId } = render(<MessageScreen />)

      const messageCards = getAllByTestId('message-card')
      fireEvent.press(messageCards[1])

      await waitFor(() => {
        expect(mockPush).toHaveBeenCalledWith(expect.stringContaining('/generationRecord'))
      })
    })

    it('should navigate to /membership when CREDITS_DEDUCTED message is clicked', async () => {
      const { getAllByTestId } = render(<MessageScreen />)

      const messageCards = getAllByTestId('message-card')
      fireEvent.press(messageCards[2])

      await waitFor(() => {
        expect(mockPush).toHaveBeenCalledWith(expect.stringContaining('/membership'))
      })
    })

    it('should mark message as read when clicked', async () => {
      const { getAllByTestId } = render(<MessageScreen />)

      const messageCards = getAllByTestId('message-card')
      fireEvent.press(messageCards[0])

      await waitFor(() => {
        expect(mockMarkRead).toHaveBeenCalledWith('1')
      })
    })

    it('should not call markRead for already read messages', async () => {
      const { getAllByTestId } = render(<MessageScreen />)

      const messageCards = getAllByTestId('message-card')
      fireEvent.press(messageCards[1]) // This is the read message

      await waitFor(() => {
        expect(mockMarkRead).not.toHaveBeenCalledWith('2')
      })
    })
  })

  describe('Pagination', () => {
    it('should call loadMore when scrolling to bottom', async () => {
      const { getByTestId } = render(<MessageScreen />)

      const flatList = getByTestId('message-list')

      fireEvent(flatList, 'onEndReached')

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

  describe('Loading State', () => {
    it('should show loading state when loading is true and no messages', () => {
      const { useMessages } = require('@/hooks/use-messages')
      useMessages.mockReturnValue({
        messages: [],
        loading: true,
        loadingMore: false,
        error: null,
        execute: mockExecute,
        refetch: mockRefetch,
        loadMore: mockLoadMore,
        hasMore: true,
      })

      const { UNSAFE_queryAllByType } = render(<MessageScreen />)
      const loadingStates = UNSAFE_queryAllByType('LoadingState' as any)
      expect(loadingStates.length).toBeGreaterThan(0)
    })
  })

  describe('Error State', () => {
    it('should show error state when error exists and no messages', () => {
      const { useMessages } = require('@/hooks/use-messages')
      useMessages.mockReturnValue({
        messages: [],
        loading: false,
        loadingMore: false,
        error: { message: 'Network error' },
        execute: mockExecute,
        refetch: mockRefetch,
        loadMore: mockLoadMore,
        hasMore: false,
      })

      const { UNSAFE_queryAllByType } = render(<MessageScreen />)
      const errorStates = UNSAFE_queryAllByType('ErrorState' as any)
      expect(errorStates.length).toBeGreaterThan(0)
    })
  })

  describe('Initial Data Fetch', () => {
    it('should call refetch on mount via useFocusEffect', () => {
      render(<MessageScreen />)
      // 现在使用 useFocusEffect + refetch 替代 useEffect + execute
      expect(mockRefetch).toHaveBeenCalled()
    })

    it('should call announcement execute on mount', () => {
      render(<MessageScreen />)
      expect(mockAnnouncementExecute).toHaveBeenCalled()
    })
  })

  describe('Pull-to-Refresh', () => {
    beforeEach(() => {
      jest.clearAllMocks()
      const { useMessages } = require('@/hooks/use-messages')
      useMessages.mockReturnValue({
        messages: mockMessages,
        loading: false,
        loadingMore: false,
        refreshing: false,
        error: null,
        execute: mockExecute,
        refetch: mockRefetch,
        loadMore: mockLoadMore,
        hasMore: true,
      })

      const { useAnnouncements } = require('@/hooks/use-announcements')
      useAnnouncements.mockReturnValue({
        announcements: mockAnnouncements,
        loading: false,
        error: null,
        execute: mockAnnouncementExecute,
        refetch: jest.fn(),
        loadMore: jest.fn(),
        hasMore: false,
      })
    })

    it('should render FlatList with RefreshControl', () => {
      const { getByTestId } = render(<MessageScreen />)
      const flatList = getByTestId('message-list')
      expect(flatList.props.refreshControl).toBeTruthy()
    })

    it('should call refetch when pull-to-refresh is triggered', async () => {
      const { getByTestId } = render(<MessageScreen />)
      const flatList = getByTestId('message-list')

      // 触发 onRefresh
      const refreshControl = flatList.props.refreshControl
      refreshControl.props.onRefresh()

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

    it('should call executeAnnouncements when pull-to-refresh is triggered', async () => {
      const { getByTestId } = render(<MessageScreen />)
      const flatList = getByTestId('message-list')

      // 触发 onRefresh
      const refreshControl = flatList.props.refreshControl
      refreshControl.props.onRefresh()

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

    it('should show refreshing indicator when refreshing is true', () => {
      const { useMessages } = require('@/hooks/use-messages')
      useMessages.mockReturnValue({
        messages: mockMessages,
        loading: false,
        loadingMore: false,
        refreshing: true,
        error: null,
        execute: mockExecute,
        refetch: mockRefetch,
        loadMore: mockLoadMore,
        hasMore: true,
      })

      const { getByTestId } = render(<MessageScreen />)
      const flatList = getByTestId('message-list')
      const refreshControl = flatList.props.refreshControl

      expect(refreshControl.props.refreshing).toBe(true)
    })

    it('should not show refreshing indicator when refreshing is false', () => {
      const { getByTestId } = render(<MessageScreen />)
      const flatList = getByTestId('message-list')
      const refreshControl = flatList.props.refreshControl

      expect(refreshControl.props.refreshing).toBe(false)
    })
  })

  describe('Tab Focus Reload', () => {
    beforeEach(() => {
      jest.clearAllMocks()
      const { useMessages } = require('@/hooks/use-messages')
      useMessages.mockReturnValue({
        messages: mockMessages,
        loading: false,
        loadingMore: false,
        refreshing: false,
        error: null,
        execute: mockExecute,
        refetch: mockRefetch,
        loadMore: mockLoadMore,
        hasMore: true,
      })

      const { useAnnouncements } = require('@/hooks/use-announcements')
      useAnnouncements.mockReturnValue({
        announcements: mockAnnouncements,
        loading: false,
        error: null,
        execute: mockAnnouncementExecute,
        refetch: jest.fn(),
        loadMore: jest.fn(),
        hasMore: false,
      })
    })

    it('should call refetch when tab gains focus', () => {
      render(<MessageScreen />)

      // useFocusEffect 在 mock 中会立即执行 callback
      // 所以 refetch 应该被调用
      expect(mockRefetch).toHaveBeenCalled()
    })

    it('should call executeAnnouncements when tab gains focus', () => {
      render(<MessageScreen />)

      expect(mockAnnouncementExecute).toHaveBeenCalled()
    })

    it('should use useFocusEffect hook', () => {
      render(<MessageScreen />)

      // 验证 useFocusEffect 被调用
      expect(mockUseFocusEffect).toHaveBeenCalled()
    })
  })
})
