/* eslint-disable @typescript-eslint/no-explicit-any */
import { fireEvent, screen } from '@testing-library/vue';
import FreeAiCreditsCallout from '@/components/FreeAiCreditsCallout.vue';
import { useCredentialsStore } from '@/stores/credentials.store';
import { useSettingsStore } from '@/stores/settings.store';
import { useUsersStore } from '@/stores/users.store';
import { useNDVStore } from '@/stores/ndv.store';
import { usePostHog } from '@/stores/posthog.store';
import { useProjectsStore } from '@/stores/projects.store';
import { useRootStore } from '@/stores/root.store';
import { useToast } from '@/composables/useToast';
import { renderComponent } from '@/__tests__/render';
import { mockedStore } from '@/__tests__/utils';
import { useTelemetry } from '@/composables/useTelemetry';

vi.mock('@/composables/useToast', () => ({
	useToast: vi.fn(),
}));

vi.mock('@/composables/useTelemetry', () => ({
	useTelemetry: vi.fn(),
}));

vi.mock('@/stores/settings.store', () => ({
	useSettingsStore: vi.fn(),
}));

vi.mock('@/stores/credentials.store', () => ({
	useCredentialsStore: vi.fn(),
}));

vi.mock('@/stores/users.store', () => ({
	useUsersStore: vi.fn(),
}));

vi.mock('@/stores/ndv.store', () => ({
	useNDVStore: vi.fn(),
}));

vi.mock('@/stores/posthog.store', () => ({
	usePostHog: vi.fn(),
}));

vi.mock('@/stores/projects.store', () => ({
	useProjectsStore: vi.fn(),
}));

vi.mock('@/stores/root.store', () => ({
	useRootStore: vi.fn(),
}));

const assertUserCannotClaimCredits = () => {
	expect(screen.queryByText('Get 100 free OpenAI API credits')).not.toBeInTheDocument();
	expect(screen.queryByRole('button', { name: 'Claim credits' })).not.toBeInTheDocument();
};

const assertUserCanClaimCredits = () => {
	expect(screen.getByText('Get 100 free OpenAI API credits')).toBeInTheDocument();
	expect(screen.queryByRole('button', { name: 'Claim credits' })).toBeInTheDocument();
};

const assertUserClaimedCredits = () => {
	expect(
		screen.getByText(
			'Claimed 100 free OpenAI API credits! Please note these free credits are only for the following models:',
		),
	).toBeInTheDocument();

	expect(
		screen.getByText(
			'gpt-4o-mini, text-embedding-3-small, dall-e-3, tts-1, whisper-1, and text-moderation-latest',
		),
	).toBeInTheDocument();
};

describe('FreeAiCreditsCallout', () => {
	beforeEach(() => {
		vi.clearAllMocks();

		(useSettingsStore as any).mockReturnValue({
			isAiCreditsEnabled: true,
			aiCreditsQuota: 100,
		});

		(useCredentialsStore as any).mockReturnValue({
			allCredentials: [],
			upsertCredential: vi.fn(),
			claimFreeAiCredits: vi.fn(),
		});

		(useUsersStore as any).mockReturnValue({
			currentUser: {
				settings: {
					userClaimedAiCredits: false,
				},
			},
		});

		(useNDVStore as any).mockReturnValue({
			activeNode: { type: '@n8n/n8n-nodes-langchain.openAi' },
		});

		(usePostHog as any).mockReturnValue({
			getVariant: vi.fn().mockReturnValue('variant'),
		});

		(useProjectsStore as any).mockReturnValue({
			currentProject: { id: 'test-project-id' },
		});

		(useRootStore as any).mockReturnValue({
			restApiContext: {},
		});

		(useToast as any).mockReturnValue({
			showError: vi.fn(),
		});

		(useTelemetry as any).mockReturnValue({
			track: vi.fn(),
		});
	});

	it('should shows the claim callout when the user can claim credits', () => {
		renderComponent(FreeAiCreditsCallout);

		assertUserCanClaimCredits();
	});

	it('should show success callout when credit are claimed', async () => {
		const credentialsStore = mockedStore(useCredentialsStore);

		renderComponent(FreeAiCreditsCallout);

		const claimButton = screen.getByRole('button', {
			name: 'Claim credits',
		});

		await fireEvent.click(claimButton);

		expect(credentialsStore.claimFreeAiCredits).toHaveBeenCalledWith('test-project-id');
		expect(useTelemetry().track).toHaveBeenCalledWith('User claimed OpenAI credits');
		assertUserClaimedCredits();
	});

	it('should not be able to claim credits is user already claimed credits', async () => {
		(useUsersStore as any).mockReturnValue({
			currentUser: {
				settings: {
					userClaimedAiCredits: true,
				},
			},
		});

		renderComponent(FreeAiCreditsCallout);

		assertUserCannotClaimCredits();
	});

	it('should not be able to claim credits is user does not have ai credits enabled', async () => {
		(useSettingsStore as any).mockReturnValue({
			isAiCreditsEnabled: false,
			aiCreditsQuota: 0,
		});

		renderComponent(FreeAiCreditsCallout);

		assertUserCannotClaimCredits();
	});

	it('should not be able to claim credits if user it is not in experiment', async () => {
		(usePostHog as any).mockReturnValue({
			getVariant: vi.fn().mockReturnValue('control'),
		});

		renderComponent(FreeAiCreditsCallout);

		assertUserCannotClaimCredits();
	});

	it('should not be able to claim credits if user already has OpenAiApi credential', async () => {
		(useCredentialsStore as any).mockReturnValue({
			allCredentials: [
				{
					type: 'openAiApi',
				},
			],
			upsertCredential: vi.fn(),
		});

		renderComponent(FreeAiCreditsCallout);

		assertUserCannotClaimCredits();
	});

	it('should not be able to claim credits if active node it is not a valid node', async () => {
		(useNDVStore as any).mockReturnValue({
			activeNode: { type: '@n8n/n8n-nodes.jira' },
		});

		renderComponent(FreeAiCreditsCallout);

		assertUserCannotClaimCredits();
	});
});
