import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
import { getFunctionName } from 'convex/server';
import { afterEach, describe, expect, it, vi } from 'vitest';

import { api } from '@spoon/backend/convex/_generated/api.js';

import { toast } from 'sonner';

import { AiProviderProfilesPanel } from '../../src/components/integrations/ai-provider-profiles-panel';

// Radix Select (rendered by the panel form) relies on ResizeObserver, which
// jsdom does not implement.
class ResizeObserverStub {
  observe = vi.fn();
  unobserve = vi.fn();
  disconnect = vi.fn();
}
globalThis.ResizeObserver ??= ResizeObserverStub as never;

const { mockUseAction, mockUseMutation, mockUseQuery } = vi.hoisted(() => ({
  mockUseAction: vi.fn(),
  mockUseMutation: vi.fn(),
  mockUseQuery: vi.fn(),
}));

vi.mock('convex/react', () => ({
  useAction: mockUseAction,
  useMutation: mockUseMutation,
  useQuery: mockUseQuery,
}));

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

const profile = {
  _id: 'profile-1',
  name: 'OpenAI',
  provider: 'openai',
  authType: 'api_key',
  secretPreview: 'sk-***',
  defaultModel: 'gpt-4o',
  reasoningEffort: 'medium',
  isDefault: true,
  enabled: true,
  configured: true,
  baseUrl: undefined,
  modelOptions: ['gpt-4o'],
};

const removeName = getFunctionName(api.aiProviderProfiles.remove);

const setup = (removeSpy: ReturnType<typeof vi.fn>) => {
  mockUseAction.mockReturnValue(vi.fn());
  mockUseQuery.mockReturnValue([profile]);
  mockUseMutation.mockImplementation((ref: Parameters<typeof getFunctionName>[0]) => {
    if (getFunctionName(ref) === removeName) return removeSpy;
    return vi.fn();
  });
};

afterEach(() => {
  cleanup();
  vi.clearAllMocks();
});

describe('AiProviderProfilesPanel remove handler', () => {
  it('shows an error toast and no success toast when the remove mutation rejects', async () => {
    const removeSpy = vi.fn().mockRejectedValue(new Error('boom'));
    setup(removeSpy);
    render(<AiProviderProfilesPanel />);

    fireEvent.click(screen.getByRole('button', { name: /remove provider/i }));

    await waitFor(() => expect(toast.error).toHaveBeenCalled());
    expect(removeSpy).toHaveBeenCalledWith({ profileId: 'profile-1' });
    expect(toast.error).toHaveBeenCalledWith('boom');
    expect(toast.success).not.toHaveBeenCalled();
  });

  it('shows a success toast only after the remove mutation resolves', async () => {
    const removeSpy = vi.fn().mockResolvedValue(undefined);
    setup(removeSpy);
    render(<AiProviderProfilesPanel />);

    fireEvent.click(screen.getByRole('button', { name: /remove provider/i }));

    await waitFor(() =>
      expect(toast.success).toHaveBeenCalledWith('AI provider removed.'),
    );
    expect(toast.error).not.toHaveBeenCalled();
  });
});
