import { configureStore } from '@reduxjs/toolkit';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Provider } from 'react-redux';
import { MemoryRouter } from 'react-router-dom';
import { beforeEach, describe, expect, it, vi } from 'vitest';

import { I18nProvider } from '../../../lib/i18n/I18nContext';
import type { Locale } from '../../../lib/i18n/types';
import localeReducer from '../../../store/localeSlice';
import SettingsHome from '../SettingsHome';

function makeTestStore(locale: Locale = 'en') {
  return configureStore({
    reducer: { locale: localeReducer },
    preloadedState: { locale: { current: locale } },
  });
}

// --- hoisted mocks ---

const { mockNavigate, mockNavigateToSettings } = vi.hoisted(() => ({
  mockNavigate: vi.fn(),
  mockNavigateToSettings: vi.fn(),
}));

vi.mock('react-router-dom', async importOriginal => {
  const actual = await importOriginal<typeof import('react-router-dom')>();
  return { ...actual, useNavigate: () => mockNavigate };
});

vi.mock('../hooks/useSettingsNavigation', () => ({
  useSettingsNavigation: () => ({ navigateToSettings: mockNavigateToSettings }),
}));

vi.mock('../../../providers/CoreStateProvider', () => ({
  useCoreState: () => ({
    clearSession: vi.fn().mockResolvedValue(undefined),
    snapshot: { auth: { userId: null }, currentUser: null },
  }),
}));

vi.mock('../../../store', () => ({ persistor: { purge: vi.fn().mockResolvedValue(undefined) } }));

vi.mock('../../../utils/links', () => ({ BILLING_DASHBOARD_URL: 'https://billing.example.com' }));

vi.mock('../../../utils/openUrl', () => ({ openUrl: vi.fn().mockResolvedValue(undefined) }));

vi.mock('../../../utils/tauriCommands', () => ({
  resetOpenHumanDataAndRestartCore: vi.fn().mockResolvedValue(undefined),
  restartApp: vi.fn().mockResolvedValue(undefined),
  scheduleCefProfilePurge: vi.fn().mockResolvedValue(undefined),
}));

const { mockClearAllAppData } = vi.hoisted(() => ({
  mockClearAllAppData: vi.fn().mockResolvedValue(undefined),
}));
vi.mock('../../../utils/clearAllAppData', () => ({
  clearAllAppData: (...args: unknown[]) => mockClearAllAppData(...args),
}));

vi.mock('../../walkthrough/AppWalkthrough', () => ({ resetWalkthrough: vi.fn() }));

// --- helpers ---

function renderSettingsHome({ locale = 'en', withI18n = false } = {}) {
  const content = withI18n ? (
    <I18nProvider>
      <SettingsHome />
    </I18nProvider>
  ) : (
    <SettingsHome />
  );

  return render(
    <Provider store={makeTestStore(locale as Locale)}>
      <MemoryRouter>{content}</MemoryRouter>
    </Provider>
  );
}

// --- tests ---

describe('SettingsHome', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('flat menu', () => {
    // Section headers ("General", "Features & AI", "Billing & Rewards",
    // "Support", "Danger Zone") were intentionally removed — the menu is
    // now a single flat list to reduce visual noise.
    it.each(['General', 'Features & AI', 'Billing & Rewards', 'Support', 'Danger Zone'])(
      'does not render section header: %s',
      label => {
        renderSettingsHome();
        expect(screen.queryByText(label)).not.toBeInTheDocument();
      }
    );

    it('renders the core menu items in a single list', () => {
      renderSettingsHome();
      expect(screen.getByText('Account')).toBeInTheDocument();
      expect(screen.getByText('Alerts')).toBeInTheDocument();
      expect(screen.getByText('Notifications')).toBeInTheDocument();
      expect(screen.getByText('Billing & Usage')).toBeInTheDocument();
      expect(screen.getByText('Advanced')).toBeInTheDocument();
      expect(screen.getByText('Clear App Data')).toBeInTheDocument();
      expect(screen.getByText('Log out')).toBeInTheDocument();
      expect(screen.getByTestId('settings-nav-account')).toBeInTheDocument();
      expect(screen.getByTestId('settings-nav-notifications')).toBeInTheDocument();
    });

    it('localizes Appearance and Mascot menu items', () => {
      renderSettingsHome({ locale: 'zh-CN', withI18n: true });

      expect(screen.getByText('外观')).toBeInTheDocument();
      expect(screen.getByText('选择浅色、深色或跟随系统主题')).toBeInTheDocument();
      expect(screen.getByText('吉祥物')).toBeInTheDocument();
      expect(screen.getByText('选择应用内使用的吉祥物颜色')).toBeInTheDocument();
    });

    it('no longer renders Features / AI / Rewards / Restart Tour / About on the home screen', () => {
      renderSettingsHome();
      expect(screen.queryByText('Features')).not.toBeInTheDocument();
      expect(screen.queryByText('AI Configuration')).not.toBeInTheDocument();
      expect(screen.queryByText('Rewards')).not.toBeInTheDocument();
      expect(screen.queryByText('Restart Tour')).not.toBeInTheDocument();
      expect(screen.queryByText('About')).not.toBeInTheDocument();
    });
  });

  describe('language selector', () => {
    it('offers Bahasa Indonesia as a display language', () => {
      renderSettingsHome();

      expect(screen.getByRole('option', { name: /Bahasa Indonesia/ })).toHaveValue('id');
    });
  });

  describe('existing navigation items', () => {
    it('navigates to account settings when Account is clicked', async () => {
      const user = userEvent.setup();
      renderSettingsHome();

      await user.click(screen.getByText('Account').closest('button')!);
      expect(mockNavigateToSettings).toHaveBeenCalledWith('account');
    });

    it('navigates to notifications settings when Notifications is clicked', async () => {
      const user = userEvent.setup();
      renderSettingsHome();

      await user.click(screen.getByText('Notifications').closest('button')!);
      expect(mockNavigateToSettings).toHaveBeenCalledWith('notifications');
    });

    it('navigates to /notifications inbox when Alerts is clicked', async () => {
      const user = userEvent.setup();
      renderSettingsHome();

      await user.click(screen.getByText('Alerts').closest('button')!);
      expect(mockNavigate).toHaveBeenCalledWith('/notifications');
    });

    it('opens billing URL when Billing & Usage is clicked', async () => {
      const { openUrl } = await import('../../../utils/openUrl');
      const user = userEvent.setup();
      renderSettingsHome();

      await user.click(screen.getByText('Billing & Usage').closest('button')!);
      expect(openUrl).toHaveBeenCalledWith('https://billing.example.com');
    });

    it('navigates to developer-options when Advanced is clicked', async () => {
      const user = userEvent.setup();
      renderSettingsHome();

      await user.click(screen.getByText('Advanced').closest('button')!);
      expect(mockNavigateToSettings).toHaveBeenCalledWith('developer-options');
    });
  });

  describe('Clear App Data flow', () => {
    beforeEach(() => {
      mockClearAllAppData.mockReset().mockResolvedValue(undefined);
    });

    it('passes the current snapshot user id + clearSession to clearAllAppData', async () => {
      const user = userEvent.setup();
      renderSettingsHome();

      await user.click(screen.getByText('Clear App Data').closest('button')!);
      // Confirm in the modal
      const confirmButtons = screen.getAllByRole('button', { name: /Clear App Data/i });
      // The last one is the modal confirm button (first is the menu item we just clicked).
      await user.click(confirmButtons[confirmButtons.length - 1]);

      expect(mockClearAllAppData).toHaveBeenCalledTimes(1);
      const args = mockClearAllAppData.mock.calls[0][0];
      expect(args).toMatchObject({ userId: null });
      expect(typeof args.clearSession).toBe('function');
    });

    it('surfaces the core error message when clearAllAppData fails (Windows file-lock guidance)', async () => {
      const user = userEvent.setup();
      mockClearAllAppData.mockRejectedValueOnce(
        new Error(
          'Failed to remove C:\\Users\\me\\.openhuman because it is locked by another OpenHuman window or process. Close all OpenHuman windows and try again.'
        )
      );
      renderSettingsHome();

      await user.click(screen.getByText('Clear App Data').closest('button')!);
      const confirmButtons = screen.getAllByRole('button', { name: /Clear App Data/i });
      await user.click(confirmButtons[confirmButtons.length - 1]);

      expect(
        await screen.findByText(/locked by another OpenHuman window or process/)
      ).toBeInTheDocument();
    });

    it('falls back to the translated message when the error has no message', async () => {
      const user = userEvent.setup();
      mockClearAllAppData.mockRejectedValueOnce(new Error(''));
      renderSettingsHome();

      await user.click(screen.getByText('Clear App Data').closest('button')!);
      const confirmButtons = screen.getAllByRole('button', { name: /Clear App Data/i });
      await user.click(confirmButtons[confirmButtons.length - 1]);

      expect(await screen.findByText(/Failed to clear data and logout/)).toBeInTheDocument();
    });
  });
});
