import { QueryClient, QueryClientProvider, useMutation, useQuery } from '@tanstack/react-query';
import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
import { afterEach, expect, test, vi } from 'vitest';
import { getAccessToken, PLATFORM_UNAUTHORIZED_EVENT, setAccessToken } from './session';
import { AuthGate, usePlatformSession } from './AuthGate';

const mocks = vi.hoisted(() => ({ session: vi.fn(), login: vi.fn(), logout: vi.fn() }));
vi.mock('../../api/client', () => ({ api: { session: mocks.session, login: mocks.login, logout: mocks.logout } }));

function ProtectedWorkspace({ onAbort }: { onAbort: () => void }) {
  const { session, logout } = usePlatformSession();
  useQuery({
    queryKey: ['protected-vehicle-data'],
    queryFn: ({ signal }) => new Promise(() => signal.addEventListener('abort', onAbort, { once: true })),
    retry: false
  });
  const mutation = useMutation({ mutationFn: async () => ({ ok: true }) });
  return <div><strong>{session.name}</strong><button type="button" onClick={() => mutation.mutate()}>创建处置缓存</button><button type="button" onClick={logout}>退出测试会话</button></div>;
}

afterEach(() => {
  cleanup();
  mocks.session.mockReset();
  mocks.login.mockReset();
  mocks.logout.mockReset();
  mocks.logout.mockResolvedValue({ loggedOut: true });
  window.sessionStorage.clear();
});

test('treats login and logout as complete query and mutation cache boundaries', async () => {
  mocks.logout.mockResolvedValue({ loggedOut: true });
  const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
  client.setQueryData(['previous-user-vehicle-data'], { plate: '粤A00001' });
  client.getMutationCache().build(client, { mutationFn: async () => ({ ok: true }) });
  const aborted = vi.fn();
  mocks.session.mockImplementation(async () => {
    if (getAccessToken() !== 'next-user-token') throw new Error('未登录');
    return { name: 'next-user', role: 'viewer', authMode: 'enforce' };
  });
  mocks.login.mockResolvedValue({ accessToken: 'next-user-token', expiresAt: new Date().toISOString(), session: { name: 'next-user', role: 'customer' } });

  render(<QueryClientProvider client={client}><AuthGate><ProtectedWorkspace onAbort={aborted} /></AuthGate></QueryClientProvider>);
  fireEvent.change(await screen.findByPlaceholderText('请输入用户名'), { target: { value: 'next-user' } });
  fireEvent.change(screen.getByPlaceholderText('请输入密码'), { target: { value: 'StrongPass!1' } });
  fireEvent.click(screen.getByRole('button', { name: '登录' }));

  expect(await screen.findByText('next-user')).toBeInTheDocument();
  expect(client.getQueryData(['previous-user-vehicle-data'])).toBeUndefined();
  expect(client.getMutationCache().getAll()).toHaveLength(0);
  await waitFor(() => expect(client.getQueryCache().find({ queryKey: ['protected-vehicle-data'] })).toBeDefined());
  fireEvent.click(screen.getByRole('button', { name: '创建处置缓存' }));
  await waitFor(() => expect(client.getMutationCache().getAll()).toHaveLength(1));

  fireEvent.click(screen.getByRole('button', { name: '退出测试会话' }));
  expect(await screen.findByPlaceholderText('请输入用户名')).toBeInTheDocument();
  await waitFor(() => expect(aborted).toHaveBeenCalledTimes(1));
  expect(client.getQueryCache().find({ queryKey: ['protected-vehicle-data'] })).toBeUndefined();
  expect(client.getMutationCache().getAll()).toHaveLength(0);
  expect(window.sessionStorage.length).toBe(0);
});

test('an expired protected request returns to login and removes the active user cache', async () => {
  mocks.logout.mockResolvedValue({ loggedOut: true });
  const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
  setAccessToken('next-user-token');
  mocks.session.mockImplementation(async () => {
    if (getAccessToken() !== 'next-user-token') throw new Error('未登录');
    return { name: 'active-user', role: 'viewer', authMode: 'enforce' };
  });

  render(<QueryClientProvider client={client}><AuthGate><ProtectedWorkspace onAbort={() => undefined} /></AuthGate></QueryClientProvider>);
  expect(await screen.findByText('active-user')).toBeInTheDocument();
  client.setQueryData(['active-user-detail'], { plate: '粤A00002' });
  window.dispatchEvent(new Event(PLATFORM_UNAUTHORIZED_EVENT));

  expect(await screen.findByPlaceholderText('请输入用户名')).toBeInTheDocument();
  expect(client.getQueryCache().find({ queryKey: ['active-user-detail'] })).toBeUndefined();
  expect(getAccessToken()).toBe('');
});
