import { cleanup, render, screen } 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 { GithubIntegrationPanel } from '../../src/components/integrations/github-integration-panel';

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

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

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

type ConnectionStatus = 'active' | 'needs_reauth' | 'revoked';

const setup = (status: ConnectionStatus) => {
  mockUseAction.mockReturnValue(vi.fn());
  const connectionName = getFunctionName(api.github.getConnection);
  const installUrlName = getFunctionName(api.github.getInstallUrl);
  mockUseQuery.mockImplementation((ref: Parameters<typeof getFunctionName>[0]) => {
    const name = getFunctionName(ref);
    if (name === connectionName) {
      return {
        _id: 'connection-1',
        displayName: 'octocat',
        installationId: '12345',
        status,
      };
    }
    if (name === installUrlName) {
      return 'https://github.com/apps/spoon/installations/new';
    }
    return undefined;
  });
};

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

describe('GithubIntegrationPanel', () => {
  it('shows the reconnect warning when the connection needs re-authorization', () => {
    setup('needs_reauth');
    render(<GithubIntegrationPanel />);

    expect(
      screen.getByText(/GitHub access needs re-authorization/i),
    ).toBeInTheDocument();
    expect(
      screen.getByRole('link', { name: /reconnect github app/i }),
    ).toBeInTheDocument();
  });

  it('shows the removed-installation warning when the connection is revoked', () => {
    setup('revoked');
    render(<GithubIntegrationPanel />);

    expect(
      screen.getByText(/GitHub App installation removed/i),
    ).toBeInTheDocument();
    expect(
      screen.getByRole('link', { name: /reconnect github app/i }),
    ).toBeInTheDocument();
  });

  it('renders the normal connected state without a warning when active', () => {
    setup('active');
    render(<GithubIntegrationPanel />);

    expect(screen.getByText('octocat')).toBeInTheDocument();
    expect(
      screen.queryByText(/needs re-authorization/i),
    ).not.toBeInTheDocument();
    expect(
      screen.queryByRole('link', { name: /reconnect github app/i }),
    ).not.toBeInTheDocument();
  });
});
