import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import Setup from '@/pages/Setup';
import { useAuthStore } from '@/stores/auth';
import { useOpencodeStore } from '@/stores/opencode';
import { useSettingsStore } from '@/stores/settings';

const { hostApiFetchMock, translateMock } = vi.hoisted(() => ({
  hostApiFetchMock: vi.fn(),
  translateMock: vi.fn((key: string, options?: { returnObjects?: boolean }) => (
    options?.returnObjects ? [`${key}.0`, `${key}.1`, `${key}.2`] : key
  )),
}));

vi.mock('@/lib/host-api', () => ({
  hostApiFetch: (...args: unknown[]) => hostApiFetchMock(...args),
}));

vi.mock('@/lib/api-client', () => ({
  invokeIpc: vi.fn(),
}));

vi.mock('react-i18next', async (importOriginal) => {
  const actual = await importOriginal<typeof import('react-i18next')>();
  return {
    ...actual,
    useTranslation: () => ({
      t: translateMock,
    }),
  };
});

vi.mock('sonner', () => ({
  toast: {
    success: vi.fn(),
    error: vi.fn(),
  },
}));

function renderSetup() {
  return render(
    <MemoryRouter initialEntries={['/setup']}>
      <Setup />
    </MemoryRouter>,
  );
}

function resetStores() {
  useAuthStore.setState({ user: null });
  useSettingsStore.setState({
    setupComplete: false,
    theme: 'system',
    language: 'en',
    launchAtStartup: false,
    telemetryEnabled: false,
    proxyEnabled: false,
    proxyServer: '',
    proxyHttpServer: '',
    proxyHttpsServer: '',
    proxyAllServer: '',
    proxyBypassRules: '',
    sidebarCollapsed: false,
    devModeUnlocked: false,
  });
  useOpencodeStore.setState({
    status: { state: 'stopped', port: 4096 },
    health: null,
    healthCheckedAt: null,
    runtimeConfigSummary: null,
    projects: [],
    activeProject: null,
    sessions: [],
    sessionsByProjectId: {},
    selectedSessionId: null,
    sessionStatuses: {},
    sessionMessages: [],
    sessionMessagesBySessionId: {},
    streamingMessage: null,
    streamingMessagesBySessionId: {},
    streamingTools: [],
    streamingToolsBySessionId: {},
    sendingSessionId: null,
    sendingSessionIds: {},
    queuedSessionPrompts: {},
    sessionDiffs: [],
    sessionDiffLoading: false,
    sessionDiffError: null,
    fileStatuses: [],
    fileSearchResults: [],
    contentSearchResults: [],
    selectedContextFile: null,
    fileContextLoading: false,
    fileContextError: null,
    runtimeAutoStartAttempted: false,
    loading: false,
    error: null,
  });
}

describe('Setup first-run progress flow', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    resetStores();
  });

  it('greets the authenticated user by the normalized account name', () => {
    useAuthStore.setState({
      user: { username: 'zhangsan@example.com', userId: 'user-1', tenantId: null, deptId: null, authorities: [] },
    });

    renderSetup();

    expect(screen.getByRole('heading', { name: 'zhangsan，欢迎回来！' })).toBeInTheDocument();
  });

  it('renders runtime checks as a quiet progress flow without dependency details', async () => {
    hostApiFetchMock.mockResolvedValue({ state: 'stopped', port: 4096 });

    renderSetup();

    fireEvent.click(screen.getByTestId('setup-next-button'));

    expect(await screen.findByTestId('setup-runtime-progress')).toBeInTheDocument();
    expect(screen.getByRole('progressbar')).toBeInTheDocument();
    expect(screen.queryByText('runtime.nodejs')).not.toBeInTheDocument();
    expect(screen.queryByText('runtime.opencode')).not.toBeInTheDocument();
    expect(screen.queryByRole('button', { name: 'runtime.viewLogs' })).not.toBeInTheDocument();
  });

  it('shows only a retry action when runtime checks fail', async () => {
    hostApiFetchMock.mockResolvedValue({
      state: 'error',
      error: 'missing bundled runtime package at /very/noisy/path',
    });

    renderSetup();

    fireEvent.click(screen.getByTestId('setup-next-button'));

    expect(await screen.findByTestId('setup-runtime-retry')).toBeInTheDocument();
    expect(screen.queryByText(/missing bundled runtime package/)).not.toBeInTheDocument();
    expect(screen.queryByRole('button', { name: 'runtime.viewLogs' })).not.toBeInTheDocument();
  });

  it('keeps dependency installation focused on overall progress', async () => {
    hostApiFetchMock.mockResolvedValue({ state: 'stopped', port: 4096 });

    renderSetup();

    fireEvent.click(screen.getByTestId('setup-next-button'));

    await waitFor(() => expect(screen.getByTestId('setup-next-button')).toBeEnabled());
    fireEvent.click(screen.getByTestId('setup-next-button'));

    expect(await screen.findByTestId('setup-installing-progress')).toBeInTheDocument();
    expect(screen.queryByText('defaultSkills.python-env.name')).not.toBeInTheDocument();
    expect(screen.queryByText('defaultSkills.file-tools.name')).not.toBeInTheDocument();
    expect(screen.queryByRole('button', { name: 'installing.skip' })).not.toBeInTheDocument();
  });
});
