import type { GetSystemFeaturesResponse } from '@dify/contracts/api/console/system-features/types.gen'
import type { ModalContextState } from '@/context/modal-context'
import type { ProviderContextState } from '@/context/provider-context'
import type { ConsoleStateFixture } from '@/test/console/state-fixture'
import type { DeepPartial } from '@/test/console/system-features'
import { fireEvent, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { renderToString } from 'react-dom/server'
import { Plan } from '@/app/components/billing/type'
import { ACCOUNT_SETTING_TAB } from '@/app/components/header/account-setting/constants'
import AccountSection from '@/app/components/main-nav/components/account-section'
import { useModalContext } from '@/context/modal-context'
import { useProviderContext } from '@/context/provider-context'
import { useLogout } from '@/service/use-common'
import { createAccountProfileQueryClient } from '@/test/console/account-profile'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import AppSelector from '../index'

vi.mock('../../account-setting', () => ({
  default: () => <div data-testid="account-setting">AccountSetting</div>,
}))

vi.mock('../../account-about', () => ({
  default: ({ onCancel }: { onCancel: () => void }) => (
    <div data-testid="account-about">
      Version
      <button onClick={onCancel}>Close</button>
    </div>
  ),
}))

vi.mock('@/app/components/header/github-star', () => ({
  default: () => <div data-testid="github-star">GithubStar</div>,
}))

vi.mock('@/app/components/base/theme-switcher', () => ({
  default: () => (
    <button type="button" data-testid="theme-switcher-button">
      Theme switcher
    </button>
  ),
}))

const { mockSetTheme } = vi.hoisted(() => ({
  mockSetTheme: vi.fn(),
}))
const mockConsoleState = vi.hoisted(() => ({
  current: undefined as ConsoleStateFixture | undefined,
}))
const mockConsoleStateReader = vi.hoisted(() => vi.fn())
const mockUseRouter = vi.hoisted(() => vi.fn())

vi.mock('next-themes', () => ({
  useTheme: () => ({
    theme: 'system',
    setTheme: mockSetTheme,
  }),
}))

vi.mock('@/context/account-state', async () => {
  const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
  return createAccountStateModuleMock(() => mockConsoleState.current ?? {})
})
vi.mock('@/context/workspace-state', async () => {
  const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
  return createWorkspaceStateModuleMock(() => mockConsoleState.current ?? {})
})
vi.mock('@/context/permission-state', async () => {
  const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
  return createPermissionStateModuleMock(() => mockConsoleState.current ?? {})
})
vi.mock('@/context/version-state', async () => {
  const { createVersionStateModuleMock } = await import('@/test/console/state-fixture')
  return createVersionStateModuleMock(() => mockConsoleState.current ?? {})
})

vi.mock('@/context/provider-context', () => ({
  useProviderContext: vi.fn(),
}))

vi.mock('@/context/modal-context', () => ({
  useModalContext: vi.fn(),
}))

vi.mock('@/service/use-common', async (importOriginal) => ({
  ...(await importOriginal<typeof import('@/service/use-common')>()),
  useLogout: vi.fn(),
}))

vi.mock('@/next/navigation', async (importOriginal) => {
  const actual = await importOriginal<typeof import('@/next/navigation')>()
  return {
    ...actual,
    useRouter: mockUseRouter,
  }
})

// Mock config and env
const { mockConfig, mockEnv } = vi.hoisted(() => ({
  mockConfig: {
    AMPLITUDE_API_KEY: '',
    ZENDESK_WIDGET_KEY: '',
    SUPPORT_EMAIL_ADDRESS: '',
  },
  mockEnv: {
    env: {
      NEXT_PUBLIC_SITE_ABOUT: 'show',
    },
  },
}))
vi.mock('@/config', async (importOriginal) => {
  const actual = await importOriginal<typeof import('@/config')>()
  return {
    ...actual,
    get AMPLITUDE_API_KEY() {
      return mockConfig.AMPLITUDE_API_KEY
    },
    get ZENDESK_WIDGET_KEY() {
      return mockConfig.ZENDESK_WIDGET_KEY
    },
    get SUPPORT_EMAIL_ADDRESS() {
      return mockConfig.SUPPORT_EMAIL_ADDRESS
    },
    IS_DEV: false,
  }
})
vi.mock('@/env', () => mockEnv)

const baseUserProfile = {
  id: '1',
  name: 'Test User',
  email: 'test@example.com',
  avatar: '',
  avatar_url: 'avatar.png',
  is_password_set: false,
}

const baseConsoleState: ConsoleStateFixture = {
  userProfile: baseUserProfile,
  refreshUserProfile: vi.fn(),
  currentWorkspace: {
    id: '1',
    name: 'Workspace',
    plan: '',
    status: '',
    created_at: 0,
    role: 'owner',
    providers: [],
    trial_credits: 0,
    trial_credits_used: 0,
    next_credit_reset_date: 0,
  },
  isCurrentWorkspaceManager: true,
  isCurrentWorkspaceOwner: true,
  isCurrentWorkspaceEditor: true,
  isCurrentWorkspaceDatasetOperator: false,
  refreshCurrentWorkspace: vi.fn(),
  langGeniusVersionInfo: {
    current_env: 'testing',
    current_version: '0.6.0',
    latest_version: '0.6.0',
    release_date: '',
    release_notes: '',
    version: '0.6.0',
    can_auto_update: false,
  },
  isLoadingCurrentWorkspace: false,
  workspacePermissionKeys: [],
}

const setConsoleState = (value: ConsoleStateFixture) => {
  mockConsoleState.current = value
  mockConsoleStateReader.mockReturnValue(value)
}

describe('AccountDropdown', () => {
  const mockPush = vi.fn()
  const mockLogout = vi.fn()
  const mockSetShowAccountSettingModal = vi.fn()
  let deploymentEdition: GetSystemFeaturesResponse['deployment_edition'] = 'COMMUNITY'

  const renderWithRouter = (
    ui: React.ReactElement,
    options: { systemFeatures?: DeepPartial<GetSystemFeaturesResponse> } = {},
  ) => {
    const queryClient = createAccountProfileQueryClient({
      ...baseUserProfile,
      ...(mockConsoleState.current?.userProfile ?? {}),
    })
    return renderWithConsoleQuery(ui, {
      queryClient,
      systemFeatures: options.systemFeatures ?? {
        deployment_edition: deploymentEdition,
        branding: { enabled: false },
      },
    })
  }

  beforeEach(() => {
    vi.clearAllMocks()
    vi.stubGlobal('localStorage', { removeItem: vi.fn() })
    deploymentEdition = 'COMMUNITY'
    mockEnv.env.NEXT_PUBLIC_SITE_ABOUT = 'show'

    setConsoleState(baseConsoleState)
    vi.mocked(useProviderContext).mockReturnValue({
      isEducationAccount: false,
      plan: { type: Plan.sandbox },
    } as unknown as ProviderContextState)
    vi.mocked(useModalContext).mockReturnValue({
      setShowAccountSettingModal: mockSetShowAccountSettingModal,
    } as unknown as ModalContextState)
    vi.mocked(useLogout).mockReturnValue({
      mutateAsync: mockLogout,
    } as unknown as ReturnType<typeof useLogout>)
    mockUseRouter.mockReturnValue({
      push: mockPush,
    })
  })

  afterEach(() => {
    vi.unstubAllGlobals()
  })

  describe('Rendering', () => {
    it('should show the signed-in account in the main navigation menu', async () => {
      const user = userEvent.setup()
      const queryClient = createAccountProfileQueryClient({
        id: 'current-user',
        name: 'Current User',
        email: 'current@example.com',
        avatar_url: 'current-avatar.png',
      })

      renderWithConsoleQuery(<AccountSection />, {
        queryClient,
        systemFeatures: { branding: { enabled: false } },
      })

      expect(screen.getByText('Current User')).toBeInTheDocument()
      expect(screen.queryByText('Test User')).not.toBeInTheDocument()

      await user.click(screen.getByRole('button', { name: 'common.account.account' }))

      expect(await screen.findByText('current@example.com')).toBeInTheDocument()
      expect(screen.queryByText('test@example.com')).not.toBeInTheDocument()
    })

    it('should render user profile correctly', () => {
      // Act
      renderWithRouter(<AppSelector />)
      fireEvent.click(screen.getByRole('button'))

      // Assert
      expect(screen.getByText('Test User')).toBeInTheDocument()
      expect(screen.getByText('test@example.com')).toBeInTheDocument()
    })

    it('should set an accessible label on avatar trigger when menu trigger is rendered', () => {
      // Act
      renderWithRouter(<AppSelector />)

      // Assert
      expect(screen.getByRole('button', { name: 'common.account.account' })).toBeInTheDocument()
    })

    it('should keep the account trigger disabled in server-rendered markup', () => {
      const container = document.createElement('div')
      container.innerHTML = renderToString(<AppSelector />)

      expect(container.querySelector('button[aria-label="common.account.account"]')).toBeDisabled()
    })

    it('should show EDU badge for education accounts', () => {
      // Arrange
      vi.mocked(useProviderContext).mockReturnValue({
        isEducationAccount: true,
        plan: { type: Plan.sandbox },
      } as unknown as ProviderContextState)

      // Act
      renderWithRouter(<AppSelector />)
      fireEvent.click(screen.getByRole('button'))

      // Assert
      expect(screen.getByText('EDU')).toBeInTheDocument()
    })
  })

  describe('Settings and Support', () => {
    it('should trigger setShowAccountSettingModal when settings is clicked', () => {
      // Act
      renderWithRouter(<AppSelector />)
      fireEvent.click(screen.getByRole('button'))
      fireEvent.click(screen.getByText('common.userProfile.settings'))

      // Assert
      expect(mockSetShowAccountSettingModal).toHaveBeenCalled()
    })

    it('should open preferences from the account dropdown', () => {
      // Act
      renderWithRouter(<AppSelector variant="mainNav" />)
      fireEvent.click(screen.getByRole('button'))
      fireEvent.click(screen.getByText('common.settings.preferences'))

      // Assert
      expect(mockSetShowAccountSettingModal).toHaveBeenCalledWith({
        payload: ACCOUNT_SETTING_TAB.PREFERENCES,
      })
    })

    it('should show Appearance after Preferences in the main nav account dropdown', () => {
      // Act
      renderWithRouter(<AppSelector variant="mainNav" />)
      fireEvent.click(screen.getByRole('button'))

      const preferences = screen.getByText('common.settings.preferences')
      const appearance = screen.getByText('common.account.appearanceLabel')

      // Assert
      expect(preferences.compareDocumentPosition(appearance)).toBe(Node.DOCUMENT_POSITION_FOLLOWING)
      expect(
        screen.getByRole('menuitem', { name: 'common.account.appearanceLabel' }),
      ).toBeInTheDocument()
    })

    it('should show Compliance in Cloud Edition for workspace owner', () => {
      // Arrange
      deploymentEdition = 'CLOUD'
      setConsoleState({
        ...baseConsoleState,
        userProfile: { ...baseConsoleState.userProfile, name: 'User' },
        isCurrentWorkspaceOwner: true,
        langGeniusVersionInfo: {
          ...baseConsoleState.langGeniusVersionInfo,
          current_version: '0.6.0',
          latest_version: '0.6.0',
        },
      })

      // Act
      renderWithRouter(<AppSelector />)
      fireEvent.click(screen.getByRole('button'))

      // Assert
      expect(screen.getByText('common.userProfile.compliance')).toBeInTheDocument()
    })

    it('should hide Compliance in Cloud Edition when user is not workspace owner', () => {
      // Arrange
      deploymentEdition = 'CLOUD'
      setConsoleState({
        ...baseConsoleState,
        isCurrentWorkspaceOwner: false,
      })

      // Act
      renderWithRouter(<AppSelector />)
      fireEvent.click(screen.getByRole('button'))

      // Assert
      expect(screen.queryByText('common.userProfile.compliance')).not.toBeInTheDocument()
    })
  })

  describe('Actions', () => {
    it('should handle logout correctly', async () => {
      // Arrange
      mockLogout.mockResolvedValue({})

      // Act
      renderWithRouter(<AppSelector />)
      fireEvent.click(screen.getByRole('button'))
      fireEvent.click(screen.getByText('common.userProfile.logout'))

      // Assert
      await waitFor(() => {
        expect(mockLogout).toHaveBeenCalled()
        expect(mockPush).toHaveBeenCalledWith('/signin')
      })
    })

    it('should use the shutdown icon for main nav logout', () => {
      // Act
      renderWithRouter(<AppSelector variant="mainNav" />)
      fireEvent.click(screen.getByRole('button'))

      // Assert
      expect(
        screen
          .getByRole('menuitem', { name: 'common.userProfile.logout' })
          .querySelector('.i-ri-shut-down-line'),
      ).toBeInTheDocument()
    })

    it('should show About section when about button is clicked and can close it', () => {
      // Act
      renderWithRouter(<AppSelector />)
      fireEvent.click(screen.getByRole('button'))
      fireEvent.click(screen.getByText('common.userProfile.about'))

      // Assert
      expect(screen.getByTestId('account-about')).toBeInTheDocument()

      // Act
      fireEvent.click(screen.getByText('Close'))

      // Assert
      expect(screen.queryByTestId('account-about')).not.toBeInTheDocument()
    })

    it('should keep account dropdown open when clicking the theme switcher', () => {
      // Act
      renderWithRouter(<AppSelector />)
      fireEvent.click(screen.getByRole('button', { name: 'common.account.account' }))
      fireEvent.click(screen.getByTestId('theme-switcher-button'))

      // Assert
      expect(screen.getByText('common.userProfile.logout')).toBeInTheDocument()
    })
  })

  describe('Branding and Environment', () => {
    it('should hide sections when branding is enabled', () => {
      // Act
      renderWithRouter(<AppSelector />, {
        systemFeatures: { branding: { enabled: true } },
      })
      fireEvent.click(screen.getByRole('button'))

      // Assert
      expect(screen.queryByText('common.userProfile.helpCenter')).not.toBeInTheDocument()
      expect(screen.queryByText('common.userProfile.roadmap')).not.toBeInTheDocument()
    })

    it('should hide About section when NEXT_PUBLIC_SITE_ABOUT is hide', () => {
      // Arrange
      mockEnv.env.NEXT_PUBLIC_SITE_ABOUT = 'hide'

      // Act
      renderWithRouter(<AppSelector />)
      fireEvent.click(screen.getByRole('button'))

      // Assert
      expect(screen.queryByText('common.userProfile.about')).not.toBeInTheDocument()
    })
  })

  describe('Version Indicators', () => {
    it('should show orange indicator when version is not latest', () => {
      // Arrange
      setConsoleState({
        ...baseConsoleState,
        userProfile: { ...baseConsoleState.userProfile, name: 'User' },
        langGeniusVersionInfo: {
          ...baseConsoleState.langGeniusVersionInfo,
          current_version: '0.6.0',
          latest_version: '0.7.0',
        },
      })

      // Act
      renderWithRouter(<AppSelector />)
      fireEvent.click(screen.getByRole('button'))

      // Assert
      expect(
        document.querySelector('.bg-components-badge-status-light-warning-bg'),
      ).toBeInTheDocument()
    })

    it('should show green indicator when version is latest', () => {
      // Arrange
      setConsoleState({
        ...baseConsoleState,
        userProfile: { ...baseConsoleState.userProfile, name: 'User' },
        langGeniusVersionInfo: {
          ...baseConsoleState.langGeniusVersionInfo,
          current_version: '0.7.0',
          latest_version: '0.7.0',
        },
      })

      // Act
      renderWithRouter(<AppSelector />)
      fireEvent.click(screen.getByRole('button'))

      // Assert
      expect(
        document.querySelector('.bg-components-badge-status-light-success-bg'),
      ).toBeInTheDocument()
    })
  })
})
