import type { GetSystemFeaturesResponse } from '@dify/contracts/api/console/system-features/types.gen'
import type { AppContextValue } from '@/context/app-context'
import type { ModalContextState } from '@/context/modal-context'
import type { ProviderContextState } from '@/context/provider-context'
import { fireEvent, screen, waitFor } from '@testing-library/react'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { Plan } from '@/app/components/billing/type'
import { useAppContext } from '@/context/app-context'
import { useModalContext } from '@/context/modal-context'
import { useProviderContext } from '@/context/provider-context'
import { useRouter } from '@/next/navigation'
import { useLogout } from '@/service/use-common'
import AppSelector from '../index'

type DeepPartial<T> = T extends Array<infer U>
  ? Array<U>
  : T extends object
    ? { [K in keyof T]?: DeepPartial<T[K]> }
    : T

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>,
}))

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

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

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

vi.mock('@/service/use-common', () => ({
  useLogout: vi.fn(),
}))

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

vi.mock('@/context/i18n', () => ({
  useDocLink: () => (path: string) => `https://docs.dify.ai${path}`,
}))

// Mock config and env
const { mockConfig, mockEnv } = vi.hoisted(() => ({
  mockConfig: {
    IS_CLOUD_EDITION: false,
    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 IS_CLOUD_EDITION() { return mockConfig.IS_CLOUD_EDITION },
    get AMPLITUDE_API_KEY() { return mockConfig.AMPLITUDE_API_KEY },
    get isAmplitudeEnabled() { return mockConfig.IS_CLOUD_EDITION && !!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,
    IS_CE_EDITION: false,
  }
})
vi.mock('@/env', () => mockEnv)

const baseAppContextValue: AppContextValue = {
  userProfile: {
    id: '1',
    name: 'Test User',
    email: 'test@example.com',
    avatar: '',
    avatar_url: 'avatar.png',
    is_password_set: false,
  },
  mutateUserProfile: 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,
  mutateCurrentWorkspace: 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,
  },
  useSelector: vi.fn(),
  isLoadingCurrentWorkspace: false,
  isValidatingCurrentWorkspace: false,
}

describe('AccountDropdown', () => {
  const mockPush = vi.fn()
  const mockLogout = vi.fn()
  const mockSetShowAccountSettingModal = vi.fn()

  const renderWithRouter = (
    ui: React.ReactElement,
    options: { systemFeatures?: DeepPartial<GetSystemFeaturesResponse> } = {},
  ) => {
    return renderWithSystemFeatures(ui, {
      systemFeatures: options.systemFeatures ?? { branding: { enabled: false } },
    })
  }

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

    vi.mocked(useAppContext).mockReturnValue(baseAppContextValue)
    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>)
    vi.mocked(useRouter).mockReturnValue({
      push: mockPush,
      replace: vi.fn(),
      prefetch: vi.fn(),
      back: vi.fn(),
      forward: vi.fn(),
      refresh: vi.fn(),
    })
  })

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

  describe('Rendering', () => {
    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 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 show Compliance in Cloud Edition for workspace owner', () => {
      // Arrange
      mockConfig.IS_CLOUD_EDITION = true
      vi.mocked(useAppContext).mockReturnValue({
        ...baseAppContextValue,
        userProfile: { ...baseAppContextValue.userProfile, name: 'User' },
        isCurrentWorkspaceOwner: true,
        langGeniusVersionInfo: { ...baseAppContextValue.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()
    })

    // Compound AND middle-false: IS_CLOUD_EDITION=true but isCurrentWorkspaceOwner=false
    it('should hide Compliance in Cloud Edition when user is not workspace owner', () => {
      // Arrange
      mockConfig.IS_CLOUD_EDITION = true
      vi.mocked(useAppContext).mockReturnValue({
        ...baseAppContextValue,
        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 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
      vi.mocked(useAppContext).mockReturnValue({
        ...baseAppContextValue,
        userProfile: { ...baseAppContextValue.userProfile, name: 'User' },
        langGeniusVersionInfo: {
          ...baseAppContextValue.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
      vi.mocked(useAppContext).mockReturnValue({
        ...baseAppContextValue,
        userProfile: { ...baseAppContextValue.userProfile, name: 'User' },
        langGeniusVersionInfo: {
          ...baseAppContextValue.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()
    })
  })
})
