import { cleanup, render, screen } from '@testing-library/react';
import type { ReactNode } from 'react';
import { MemoryRouter } from 'react-router';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

import ModeSwitch from './ModeSwitch';

const mockConfig = vi.hoisted(() => ({
  agentOnboardingEnabled: true,
  AGENT_ONBOARDING_ENABLED: true,
  desktop: false,
  serverConfigInit: true,
}));

vi.mock('@lobechat/business-const', () => ({
  get AGENT_ONBOARDING_ENABLED() {
    return mockConfig.AGENT_ONBOARDING_ENABLED;
  },
}));

vi.mock('react-i18next', () => ({
  useTranslation: () => ({
    t: (key: string) =>
      (
        ({
          'agent.modeSwitch.agent': 'Conversational setup',
          'agent.modeSwitch.classic': 'Manual setup',
          'agent.modeSwitch.label': 'Choose a setup method',
        }) as Record<string, string>
      )[key] || key,
  }),
}));

interface RenderModeSwitchOptions {
  actions?: ReactNode;
  AGENT_ONBOARDING_ENABLED?: boolean;
  desktop?: boolean;
  enabled: boolean;
  entry?: string;
  serverConfigInit?: boolean;
  showLabel?: boolean;
}

vi.mock('@lobechat/const', () => ({
  get isDesktop() {
    return mockConfig.desktop;
  },
}));

vi.mock('@/store/serverConfig', () => ({
  useServerConfigStore: <T,>(
    selector: (state: {
      featureFlags: {
        enableAgentOnboarding: boolean;
      };
      serverConfigInit: boolean;
    }) => T,
  ) => {
    return selector({
      featureFlags: { enableAgentOnboarding: mockConfig.agentOnboardingEnabled },
      serverConfigInit: mockConfig.serverConfigInit,
    });
  },
}));

const localStorageMock = {
  clear: vi.fn(),
  getItem: vi.fn(() => null),
  removeItem: vi.fn(),
  setItem: vi.fn(),
};

const renderModeSwitch = ({
  actions,
  AGENT_ONBOARDING_ENABLED = true,
  desktop = false,
  enabled,
  entry = '/onboarding/agent',
  serverConfigInit = true,
  showLabel,
}: RenderModeSwitchOptions) => {
  mockConfig.agentOnboardingEnabled = enabled;
  mockConfig.AGENT_ONBOARDING_ENABLED = AGENT_ONBOARDING_ENABLED;
  mockConfig.desktop = desktop;
  mockConfig.serverConfigInit = serverConfigInit;

  render(
    <MemoryRouter initialEntries={[entry]}>
      <ModeSwitch actions={actions} showLabel={showLabel} />
    </MemoryRouter>,
  );
};

beforeEach(() => {
  Object.defineProperty(window, 'localStorage', {
    configurable: true,
    value: localStorageMock,
  });
});

afterEach(() => {
  cleanup();
  vi.clearAllMocks();
  mockConfig.agentOnboardingEnabled = true;
  mockConfig.AGENT_ONBOARDING_ENABLED = true;
  mockConfig.desktop = false;
  mockConfig.serverConfigInit = true;
});

// Each test does vi.resetModules() + dynamic import of the component, which
// re-parses antd + @lobehub/ui fresh. On cold CI runs this can blow past the
// default 5s timeout even though the test is doing nothing slow itself.
const TEST_TIMEOUT_MS = 15_000;

describe('ModeSwitch', () => {
  it(
    'renders both onboarding variants when agent onboarding is enabled',
    () => {
      renderModeSwitch({ enabled: true, showLabel: true });

      expect(screen.getByText('Choose a setup method')).toBeInTheDocument();
      expect(screen.getByRole('radio', { name: 'Conversational setup' })).toBeChecked();
      expect(screen.getByRole('radio', { name: 'Manual setup' })).not.toBeChecked();
    },
    TEST_TIMEOUT_MS,
  );

  it(
    'hides the onboarding switch entirely when agent onboarding is disabled',
    () => {
      renderModeSwitch({ enabled: false });

      expect(screen.queryByRole('radio', { name: 'Conversational setup' })).not.toBeInTheDocument();
      expect(screen.queryByRole('radio', { name: 'Manual setup' })).not.toBeInTheDocument();
      expect(screen.queryByText('Choose a setup method')).not.toBeInTheDocument();
    },
    TEST_TIMEOUT_MS,
  );

  it('hides the onboarding switch until server config is initialized', () => {
    renderModeSwitch({ enabled: true, serverConfigInit: false });

    expect(screen.queryByRole('radio', { name: 'Conversational setup' })).not.toBeInTheDocument();
    expect(screen.queryByRole('radio', { name: 'Manual setup' })).not.toBeInTheDocument();
  });

  it('keeps action buttons visible when agent onboarding is disabled', () => {
    renderModeSwitch({
      actions: <button type="button">Restart</button>,
      enabled: false,
    });

    expect(screen.getByRole('button', { name: 'Restart' })).toBeInTheDocument();
    expect(screen.queryByRole('radio', { name: 'Conversational setup' })).not.toBeInTheDocument();
    expect(screen.queryByRole('radio', { name: 'Manual setup' })).not.toBeInTheDocument();
  });

  it('does not render the switch on desktop builds', () => {
    renderModeSwitch({ desktop: true, enabled: true });

    expect(screen.queryByRole('radio', { name: 'Conversational setup' })).not.toBeInTheDocument();
    expect(screen.queryByRole('radio', { name: 'Manual setup' })).not.toBeInTheDocument();
  });

  it('hides the switch when AGENT_ONBOARDING_ENABLED master switch is off', () => {
    renderModeSwitch({ AGENT_ONBOARDING_ENABLED: false, enabled: true });

    expect(screen.queryByRole('radio', { name: 'Conversational setup' })).not.toBeInTheDocument();
    expect(screen.queryByRole('radio', { name: 'Manual setup' })).not.toBeInTheDocument();
  });
});
