import type { SiteInfo } from '@/models/share'
import { act, cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import MenuDropdown from '../menu-dropdown'

vi.mock('../info-modal', () => ({
  default: ({
    isShow,
    onClose,
    data,
  }: {
    isShow: boolean
    onClose: () => void
    data?: SiteInfo
  }) => {
    if (!isShow)
      return null
    return (
      <div data-testid="info-modal">
        <span>{data?.title}</span>
        <button type="button" onClick={onClose}>Close Info</button>
      </div>
    )
  },
}))

const mockReplace = vi.fn()
const mockPathname = '/test-path'
vi.mock('@/next/navigation', () => ({
  useRouter: () => ({
    replace: mockReplace,
  }),
  usePathname: () => mockPathname,
}))

const mockShareCode = 'test-share-code'
vi.mock('@/context/web-app-context', () => ({
  useWebAppStore: (selector: (state: Record<string, unknown>) => unknown) => {
    const state = {
      webAppAccessMode: 'code',
      shareCode: mockShareCode,
    }
    return selector(state)
  },
}))

const mockWebAppLogout = vi.fn().mockResolvedValue(undefined)
vi.mock('@/service/webapp-auth', () => ({
  webAppLogout: (...args: unknown[]) => mockWebAppLogout(...args),
}))

afterEach(() => {
  cleanup()
})

describe('MenuDropdown', () => {
  const baseSiteInfo: SiteInfo = {
    title: 'Test App',
    icon: '🚀',
    icon_type: 'emoji',
  }

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

  describe('rendering', () => {
    it('should render the trigger button', () => {
      render(<MenuDropdown data={baseSiteInfo} />)

      const triggerButton = screen.getByRole('button')
      expect(triggerButton).toBeInTheDocument()
    })

    it('should not show dropdown content initially', () => {
      render(<MenuDropdown data={baseSiteInfo} />)

      expect(screen.queryByText('common.theme.theme')).not.toBeInTheDocument()
    })

    it('should show dropdown content when clicked', async () => {
      render(<MenuDropdown data={baseSiteInfo} />)

      const triggerButton = screen.getByRole('button')
      fireEvent.click(triggerButton)

      await waitFor(() => {
        expect(screen.getByText('common.theme.theme')).toBeInTheDocument()
      })
    })

    it('should show About option in dropdown', async () => {
      render(<MenuDropdown data={baseSiteInfo} />)

      const triggerButton = screen.getByRole('button')
      fireEvent.click(triggerButton)

      await waitFor(() => {
        expect(screen.getByText('common.userProfile.about')).toBeInTheDocument()
      })
    })
  })

  describe('privacy policy link', () => {
    it('should show privacy policy link when provided', async () => {
      const siteInfoWithPrivacy: SiteInfo = {
        ...baseSiteInfo,
        privacy_policy: 'https://example.com/privacy',
      }

      render(<MenuDropdown data={siteInfoWithPrivacy} />)

      const triggerButton = screen.getByRole('button')
      fireEvent.click(triggerButton)

      await waitFor(() => {
        expect(screen.getByText('share.chat.privacyPolicyMiddle')).toBeInTheDocument()
      })
    })

    it('should not show privacy policy link when not provided', async () => {
      render(<MenuDropdown data={baseSiteInfo} />)

      const triggerButton = screen.getByRole('button')
      fireEvent.click(triggerButton)

      await waitFor(() => {
        expect(screen.queryByText('share.chat.privacyPolicyMiddle')).not.toBeInTheDocument()
      })
    })

    it('should have correct href for privacy policy link', async () => {
      const privacyUrl = 'https://example.com/privacy'
      const siteInfoWithPrivacy: SiteInfo = {
        ...baseSiteInfo,
        privacy_policy: privacyUrl,
      }

      render(<MenuDropdown data={siteInfoWithPrivacy} />)

      const triggerButton = screen.getByRole('button')
      fireEvent.click(triggerButton)

      await waitFor(() => {
        const link = screen.getByText('share.chat.privacyPolicyMiddle').closest('a')
        expect(link).toHaveAttribute('href', privacyUrl)
        expect(link).toHaveAttribute('target', '_blank')
      })
    })
  })

  describe('logout functionality', () => {
    it('should show logout option when hideLogout is false', async () => {
      render(<MenuDropdown data={baseSiteInfo} hideLogout={false} />)

      const triggerButton = screen.getByRole('button')
      fireEvent.click(triggerButton)

      await waitFor(() => {
        expect(screen.getByText('common.userProfile.logout')).toBeInTheDocument()
      })
    })

    it('should hide logout option when hideLogout is true', async () => {
      render(<MenuDropdown data={baseSiteInfo} hideLogout={true} />)

      const triggerButton = screen.getByRole('button')
      fireEvent.click(triggerButton)

      await waitFor(() => {
        expect(screen.queryByText('common.userProfile.logout')).not.toBeInTheDocument()
      })
    })

    it('should call webAppLogout and redirect when logout is clicked', async () => {
      render(<MenuDropdown data={baseSiteInfo} hideLogout={false} />)

      const triggerButton = screen.getByRole('button')
      fireEvent.click(triggerButton)

      await waitFor(() => {
        expect(screen.getByText('common.userProfile.logout')).toBeInTheDocument()
      })

      const logoutButton = screen.getByText('common.userProfile.logout')
      await act(async () => {
        fireEvent.click(logoutButton)
      })

      await waitFor(() => {
        expect(mockWebAppLogout).toHaveBeenCalledWith(mockShareCode)
        expect(mockReplace).toHaveBeenCalledWith(`/webapp-signin?redirect_url=${mockPathname}`)
      })
    })
  })

  describe('about modal', () => {
    it('should show InfoModal when About is clicked', async () => {
      render(<MenuDropdown data={baseSiteInfo} />)

      const triggerButton = screen.getByRole('button')
      fireEvent.click(triggerButton)

      await waitFor(() => {
        expect(screen.getByText('common.userProfile.about')).toBeInTheDocument()
      })

      const aboutButton = screen.getByText('common.userProfile.about')
      fireEvent.click(aboutButton)

      await waitFor(() => {
        expect(screen.getByText('Test App')).toBeInTheDocument()
      })
    })

    it('should close InfoModal when the close handler runs', async () => {
      render(<MenuDropdown data={baseSiteInfo} />)

      fireEvent.click(screen.getByRole('button'))
      await waitFor(() => {
        expect(screen.getByText('common.userProfile.about')).toBeInTheDocument()
      })

      fireEvent.click(screen.getByText('common.userProfile.about'))
      await waitFor(() => {
        expect(screen.getByTestId('info-modal')).toBeInTheDocument()
      })

      fireEvent.click(screen.getByText('Close Info'))
      await waitFor(() => {
        expect(screen.queryByTestId('info-modal')).not.toBeInTheDocument()
      })
    })
  })

  describe('forceClose prop', () => {
    it('should close dropdown when forceClose changes to true', async () => {
      const { rerender } = render(<MenuDropdown data={baseSiteInfo} forceClose={false} />)

      const triggerButton = screen.getByRole('button')
      fireEvent.click(triggerButton)

      await waitFor(() => {
        expect(screen.getByText('common.theme.theme')).toBeInTheDocument()
      })

      rerender(<MenuDropdown data={baseSiteInfo} forceClose={true} />)

      await waitFor(() => {
        expect(screen.queryByText('common.theme.theme')).not.toBeInTheDocument()
      })
    })
  })

  describe('placement prop', () => {
    it('should accept custom placement', () => {
      render(<MenuDropdown data={baseSiteInfo} placement="top-start" />)

      const triggerButton = screen.getByRole('button')
      expect(triggerButton).toBeInTheDocument()
    })
  })

  describe('toggle behavior', () => {
    it('should close dropdown when clicking trigger again', async () => {
      render(<MenuDropdown data={baseSiteInfo} />)

      const triggerButton = screen.getByRole('button')

      fireEvent.click(triggerButton)
      await waitFor(() => {
        expect(screen.getByText('common.theme.theme')).toBeInTheDocument()
      })

      fireEvent.click(triggerButton)
      await waitFor(() => {
        expect(screen.queryByText('common.theme.theme')).not.toBeInTheDocument()
      })
    })
  })

  describe('memoization', () => {
    it('should be wrapped with React.memo', () => {
      expect((MenuDropdown as unknown as { $$typeof: symbol }).$$typeof).toBe(Symbol.for('react.memo'))
    })
  })
})
