import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { SidebarUpdateButton } from '@/components/layout/SidebarUpdateButton';
import { useUpdateStore } from '@/stores/update';

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

describe('SidebarUpdateButton', () => {
  const init = vi.fn().mockResolvedValue(undefined);
  const downloadUpdate = vi.fn().mockResolvedValue(undefined);
  const installUpdate = vi.fn();

  beforeEach(() => {
    vi.clearAllMocks();
    downloadUpdate.mockResolvedValue(undefined);
    useUpdateStore.setState({
      status: 'idle',
      currentVersion: '0.9.1',
      updateInfo: null,
      progress: null,
      error: null,
      isInitialized: true,
      isInitializing: false,
      autoInstallCountdown: null,
      init,
      downloadUpdate,
      installUpdate,
    });
  });

  it.each(['idle', 'checking', 'not-available', 'error'] as const)(
    'stays hidden while the update status is %s',
    (status) => {
      useUpdateStore.setState({ status });
      render(<SidebarUpdateButton collapsed={false} />);

      expect(screen.queryByTestId('sidebar-update-button')).not.toBeInTheDocument();
    },
  );

  it('initializes update discovery even while the control is hidden', async () => {
    render(<SidebarUpdateButton collapsed={false} />);

    expect(screen.queryByTestId('sidebar-update-button')).not.toBeInTheDocument();
    await waitFor(() => expect(init).toHaveBeenCalledTimes(1));
  });

  it('shows the download action when an update is available', () => {
    useUpdateStore.setState({ status: 'available', updateInfo: { version: '0.9.2' } });
    render(<SidebarUpdateButton collapsed={false} />);

    expect(screen.getByTestId('sidebar-update-button')).toHaveAccessibleName('下载新版本 0.9.2');
  });

  it('downloads an available version on the first click', async () => {
    useUpdateStore.setState({ status: 'available', updateInfo: { version: '0.9.2' } });
    render(<SidebarUpdateButton collapsed={false} />);

    fireEvent.click(screen.getByRole('button', { name: '下载新版本 0.9.2' }));

    await waitFor(() => expect(downloadUpdate).toHaveBeenCalledTimes(1));
    expect(installUpdate).not.toHaveBeenCalled();
  });

  it('disables duplicate actions while downloading', () => {
    useUpdateStore.setState({ status: 'downloading', updateInfo: { version: '0.9.2' } });
    render(<SidebarUpdateButton collapsed={false} />);

    expect(screen.getByTestId('sidebar-update-button')).toBeDisabled();
    expect(screen.getByTestId('sidebar-update-button')).toHaveAccessibleName('正在下载新版本 0.9.2');
  });

  it('installs only after the update is downloaded', () => {
    useUpdateStore.setState({ status: 'downloaded', updateInfo: { version: '0.9.2' } });
    render(<SidebarUpdateButton collapsed />);

    fireEvent.click(screen.getByRole('button', { name: '重启并安装新版本 0.9.2' }));

    expect(installUpdate).toHaveBeenCalledTimes(1);
    expect(downloadUpdate).not.toHaveBeenCalled();
  });

  it('shows a bounded toast when download fails', async () => {
    downloadUpdate.mockImplementationOnce(async () => {
      useUpdateStore.setState({ status: 'error', error: 'Remote update download failed' });
    });
    useUpdateStore.setState({ status: 'available', updateInfo: { version: '0.9.2' } });
    render(<SidebarUpdateButton collapsed={false} />);

    fireEvent.click(screen.getByRole('button', { name: '下载新版本 0.9.2' }));

    await waitFor(() => expect(toastError).toHaveBeenCalledWith('更新下载失败', {
      description: 'Remote update download failed',
    }));
  });
});
