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('uses a branded Semi UI session state while restoring authentication', () => {
  mocks.session.mockReturnValue(new Promise(() => undefined));
  const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });

  const view = render(<QueryClientProvider client={client}><AuthGate><div>受保护工作台</div></AuthGate></QueryClientProvider>);

  expect(screen.getByRole('status')).toHaveTextContent('正在验证登录状态');
  expect(screen.getByRole('status')).toHaveTextContent('账号、菜单与车辆权限');
  expect(screen.getByAltText('羚牛智能')).toHaveAttribute('src', '/brand-logo.svg');
  expect(view.container.querySelector('.v2-auth-loading.semi-card')).toBeInTheDocument();
  expect(view.container.querySelectorAll('.v2-auth-loading-skeleton > i')).toHaveLength(3);
});

test('presents failed credentials as a clear Semi UI alert without losing the login form', async () => {
  mocks.session.mockRejectedValue(new Error('未登录'));
  mocks.login.mockRejectedValue(new Error('账号或密码错误'));
  const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });

  const view = render(<QueryClientProvider client={client}><AuthGate><div>受保护工作台</div></AuthGate></QueryClientProvider>);
  fireEvent.change(await screen.findByPlaceholderText('请输入用户名'), { target: { value: 'customer' } });
  fireEvent.change(screen.getByPlaceholderText('请输入密码'), { target: { value: 'wrong-password' } });
  fireEvent.click(screen.getByRole('button', { name: '登录工作台' }));

  expect(await screen.findByRole('alert')).toHaveTextContent('登录未完成');
  expect(screen.getByRole('alert')).toHaveTextContent('账号或密码错误');
  expect(view.container.querySelector('.v2-auth-error .semi-banner')).toBeInTheDocument();
  expect(screen.getByPlaceholderText('请输入用户名')).toBeInTheDocument();
});

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('makes account and operations-token entry explicit while preserving the account draft', async () => {
  const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
  mocks.session.mockImplementation(async () => {
    if (getAccessToken() !== 'ops-session-token') throw new Error('未登录');
    return { name: 'platform-operator', role: 'admin', authMode: 'enforce' };
  });

  render(<QueryClientProvider client={client}><AuthGate><ProtectedWorkspace onAbort={() => undefined} /></AuthGate></QueryClientProvider>);

  expect(await screen.findByRole('form', { name: '平台账号登录' })).toBeInTheDocument();
  expect(screen.getByRole('tab', { name: '账号登录' })).toHaveAttribute('aria-selected', 'true');
  expect(screen.getByRole('tab', { name: '运维令牌' })).toHaveAttribute('aria-selected', 'false');
  fireEvent.change(screen.getByPlaceholderText('请输入用户名'), { target: { value: 'remember-me' } });

  fireEvent.click(screen.getByRole('tab', { name: '运维令牌' }));
  expect(screen.getByRole('form', { name: '运维令牌登录' })).toBeInTheDocument();
  expect(screen.getByText('仅限平台运维')).toBeInTheDocument();
  expect(screen.getByText('令牌只保存在当前浏览器会话，关闭或退出后失效。')).toBeInTheDocument();
  expect(screen.queryByRole('button', { name: 'Close' })).not.toBeInTheDocument();
  fireEvent.change(screen.getByPlaceholderText('请输入服务器访问令牌'), { target: { value: 'ops-session-token' } });

  fireEvent.click(screen.getByRole('tab', { name: '账号登录' }));
  expect(screen.getByPlaceholderText('请输入用户名')).toHaveValue('remember-me');
  fireEvent.click(screen.getByRole('tab', { name: '运维令牌' }));
  fireEvent.click(screen.getByRole('button', { name: '验证令牌并进入' }));

  expect(await screen.findByText('platform-operator')).toBeInTheDocument();
  expect(mocks.login).not.toHaveBeenCalled();
  expect(getAccessToken()).toBe('ops-session-token');
});

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('');
});
