import { page } from 'vitest/browser';
import { describe, test, expect, vi, beforeEach } from 'vitest';
import { render } from 'vitest-browser-svelte';
import NotificationSettings from './NotificationSettings.svelte';
import { pushNotificationManager } from '$lib/client/PushNotificationManager';

// Mock the pushNotificationManager
vi.mock('$lib/client/PushNotificationManager', () => ({
	pushNotificationManager: {
		onStateChange: vi.fn(),
		toggleSubscription: vi.fn()
	}
}));

describe('NotificationSettings test buttons', () => {
	beforeEach(() => {
		vi.clearAllMocks();
		// Mock fetch using vi.stubGlobal for browser environment
		vi.stubGlobal('fetch', vi.fn());
	});

	test('should not show test buttons when not subscribed', async () => {
		vi.mocked(pushNotificationManager.onStateChange).mockImplementation((callback) => {
			callback({
				supported: true,
				permission: 'granted',
				subscribed: false,
				loading: false,
				error: null
			});
			return () => {};
		});

		render(NotificationSettings);

		// Test Notifications section should not be visible
		const testSection = page.getByText('Test Notifications');
		await expect.element(testSection).not.toBeInTheDocument();
	});

	test('should show test buttons when subscribed', async () => {
		vi.mocked(pushNotificationManager.onStateChange).mockImplementation((callback) => {
			callback({
				supported: true,
				permission: 'granted',
				subscribed: true,
				loading: false,
				error: null
			});
			return () => {};
		});

		render(NotificationSettings);

		await expect.element(page.getByText('Test Success')).toBeInTheDocument();
		await expect.element(page.getByText('Test Error')).toBeInTheDocument();
		await expect.element(page.getByText('Test Progress')).toBeInTheDocument();
	});

	test('should send test success notification on button click', async () => {
		vi.mocked(fetch).mockResolvedValue({
			ok: true,
			json: async () => ({ success: true, subscriberCount: 1 })
		} as Response);

		vi.mocked(pushNotificationManager.onStateChange).mockImplementation((callback) => {
			callback({
				supported: true,
				permission: 'granted',
				subscribed: true,
				loading: false,
				error: null
			});
			return () => {};
		});

		render(NotificationSettings);

		const button = page.getByText('Test Success');
		await button.click();

		expect(fetch).toHaveBeenCalledWith('/api/notifications/test', {
			method: 'POST',
			headers: { 'Content-Type': 'application/json' },
			body: JSON.stringify({ type: 'success' })
		});

		const successMessage = page.getByText(/✓ Test success notification sent to 1 subscriber/i);
		await expect.element(successMessage).toBeInTheDocument();
	});

	test('should send test error notification on button click', async () => {
		vi.mocked(fetch).mockResolvedValue({
			ok: true,
			json: async () => ({ success: true, subscriberCount: 2 })
		} as Response);

		vi.mocked(pushNotificationManager.onStateChange).mockImplementation((callback) => {
			callback({
				supported: true,
				permission: 'granted',
				subscribed: true,
				loading: false,
				error: null
			});
			return () => {};
		});

		render(NotificationSettings);

		const button = page.getByText('Test Error');
		await button.click();

		expect(fetch).toHaveBeenCalledWith('/api/notifications/test', {
			method: 'POST',
			headers: { 'Content-Type': 'application/json' },
			body: JSON.stringify({ type: 'error' })
		});

		const successMessage = page.getByText(/✓ Test error notification sent/i);
		await expect.element(successMessage).toBeInTheDocument();
	});

	test('should send test progress notification on button click', async () => {
		vi.mocked(fetch).mockResolvedValue({
			ok: true,
			json: async () => ({ success: true, subscriberCount: 1 })
		} as Response);

		vi.mocked(pushNotificationManager.onStateChange).mockImplementation((callback) => {
			callback({
				supported: true,
				permission: 'granted',
				subscribed: true,
				loading: false,
				error: null
			});
			return () => {};
		});

		render(NotificationSettings);

		const button = page.getByText('Test Progress');
		await button.click();

		expect(fetch).toHaveBeenCalledWith('/api/notifications/test', {
			method: 'POST',
			headers: { 'Content-Type': 'application/json' },
			body: JSON.stringify({ type: 'progress' })
		});

		const successMessage = page.getByText(/✓ Test progress notification sent/i);
		await expect.element(successMessage).toBeInTheDocument();
	});

	test('should display error message on failed request', async () => {
		vi.mocked(fetch).mockResolvedValue({
			ok: false,
			status: 500
		} as Response);

		vi.mocked(pushNotificationManager.onStateChange).mockImplementation((callback) => {
			callback({
				supported: true,
				permission: 'granted',
				subscribed: true,
				loading: false,
				error: null
			});
			return () => {};
		});

		render(NotificationSettings);

		const button = page.getByText('Test Success');
		await button.click();

		const errorMessage = page.getByText(/✗ Error:/i);
		await expect.element(errorMessage).toBeInTheDocument();
	});

	test('should auto-dismiss message after 3 seconds', async () => {
		vi.mocked(fetch).mockResolvedValue({
			ok: true,
			json: async () => ({ success: true, subscriberCount: 1 })
		} as Response);

		vi.mocked(pushNotificationManager.onStateChange).mockImplementation((callback) => {
			callback({
				supported: true,
				permission: 'granted',
				subscribed: true,
				loading: false,
				error: null
			});
			return () => {};
		});

		render(NotificationSettings);

		const button = page.getByText('Test Success');
		await button.click();

		// Message should appear
		const successMessage = page.getByText(/✓ Test success notification sent to 1 subscriber/i);
		await expect.element(successMessage).toBeInTheDocument();
	});

	test('should disable buttons during loading', async () => {
		// Create a promise that we can control
		let resolvePromise: ((value: any) => void) | undefined;
		const fetchPromise = new Promise((resolve) => {
			resolvePromise = resolve;
		});

		vi.mocked(fetch).mockReturnValue(fetchPromise as any);

		vi.mocked(pushNotificationManager.onStateChange).mockImplementation((callback) => {
			callback({
				supported: true,
				permission: 'granted',
				subscribed: true,
				loading: false,
				error: null
			});
			return () => {};
		});

		render(NotificationSettings);

		const successButton = page.getByRole('button', { name: 'Test Success' });

		// Click a button to start loading
		await successButton.click();

		// Button should show "Sending..." text
		const sendingButton = page.getByRole('button', { name: 'Sending...' }).first();
		await expect.element(sendingButton).toBeInTheDocument();

		// Cleanup - resolve the promise
		resolvePromise?.({
			ok: true,
			json: async () => ({ success: true, subscriberCount: 1 })
		});
	});
});
