/**
 * @jest-environment jsdom
 */

/*
 * Runtime Web – Unified Serverless Framework for Full-Stack TypeScript Applications
 * Documentation: https://runtimeweb.com/docs/getting-started
 *
 * @template: ai-chat
 */

/**
 * Property-based tests for EmptyState component.
 *
 * **Property 5: Empty State Rendering**
 * **Validates: Requirements 5.1, 5.3, 5.5**
 *
 * Property: For any chat state where messages array is empty and isLoading is false,
 * the EmptyState component SHALL be rendered with at least one suggested prompt button.
 * For any prompt button click, the onPromptSelect callback SHALL be invoked with the prompt text.
 *
 * @module components/chat/__tests__/EmptyState.property.test
 */

import * as React from 'react';
import * as fc from 'fast-check';
import { render, cleanup, screen, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom';
import { EmptyState } from '../EmptyState';

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

describe('EmptyState Property Tests', () => {
    /**
     * **Property 5: Empty State Rendering**
     * **Validates: Requirements 5.1, 5.3, 5.5**
     */
    describe('Property 5: Empty State Rendering', () => {
        /**
         * Validates: Requirement 5.1
         * The EmptyState SHALL be rendered with welcoming content.
         */
        it('renders with welcoming title and description', () => {
            fc.assert(
                fc.property(fc.constant(true), () => {
                    const onPromptSelect = jest.fn();
                    const { unmount } = render(<EmptyState onPromptSelect={onPromptSelect} />);

                    const emptyState = screen.getByTestId('empty-state');
                    expect(emptyState).toBeInTheDocument();

                    // Should have a title
                    const title = emptyState.querySelector('.empty-state__title');
                    expect(title).not.toBeNull();
                    expect(title?.textContent).toBeTruthy();

                    // Should have a description
                    const description = emptyState.querySelector('.empty-state__description');
                    expect(description).not.toBeNull();
                    expect(description?.textContent).toBeTruthy();

                    unmount();
                }),
                { numRuns: 10 },
            );
        });

        /**
         * Validates: Requirement 5.2
         * The EmptyState SHALL include a visually appealing icon.
         */
        it('renders with icon element', () => {
            fc.assert(
                fc.property(fc.constant(true), () => {
                    const onPromptSelect = jest.fn();
                    const { container, unmount } = render(<EmptyState onPromptSelect={onPromptSelect} />);

                    const icon = container.querySelector('.empty-state__icon');
                    expect(icon).not.toBeNull();

                    // Icon should be hidden from screen readers
                    expect(icon).toHaveAttribute('aria-hidden', 'true');

                    unmount();
                }),
                { numRuns: 10 },
            );
        });

        /**
         * Validates: Requirement 5.3
         * The EmptyState SHALL include at least one suggested prompt button.
         */
        it('renders with at least one suggested prompt button', () => {
            fc.assert(
                fc.property(fc.constant(true), () => {
                    const onPromptSelect = jest.fn();
                    const { container, unmount } = render(<EmptyState onPromptSelect={onPromptSelect} />);

                    const prompts = container.querySelectorAll('.empty-state__prompt');
                    expect(prompts.length).toBeGreaterThanOrEqual(1);

                    // Each prompt should be a button
                    prompts.forEach((prompt) => {
                        expect(prompt.tagName.toLowerCase()).toBe('button');
                    });

                    unmount();
                }),
                { numRuns: 10 },
            );
        });

        /**
         * Validates: Requirement 5.3
         * Each suggested prompt SHALL have visible text content.
         */
        it('each prompt has visible text content', () => {
            fc.assert(
                fc.property(fc.constant(true), () => {
                    const onPromptSelect = jest.fn();
                    const { container, unmount } = render(<EmptyState onPromptSelect={onPromptSelect} />);

                    const prompts = container.querySelectorAll('.empty-state__prompt');

                    prompts.forEach((prompt) => {
                        const textElement = prompt.querySelector('.empty-state__prompt-text');
                        expect(textElement).not.toBeNull();
                        expect(textElement?.textContent?.trim()).toBeTruthy();
                    });

                    unmount();
                }),
                { numRuns: 10 },
            );
        });

        /**
         * Validates: Requirement 5.5
         * For any prompt button click, onPromptSelect SHALL be invoked with the prompt text.
         */
        it('clicking a prompt invokes onPromptSelect with the prompt text', () => {
            fc.assert(
                fc.property(fc.integer({ min: 0, max: 3 }), (promptIndex) => {
                    const onPromptSelect = jest.fn();
                    const { unmount } = render(<EmptyState onPromptSelect={onPromptSelect} />);

                    const promptButton = screen.getByTestId(`empty-state-prompt-${promptIndex}`);
                    const promptText = promptButton.querySelector('.empty-state__prompt-text')?.textContent;

                    fireEvent.click(promptButton);

                    expect(onPromptSelect).toHaveBeenCalledTimes(1);
                    expect(onPromptSelect).toHaveBeenCalledWith(promptText);

                    unmount();
                }),
                { numRuns: 20 },
            );
        });

        /**
         * Validates: Requirement 5.5
         * Each prompt button click SHALL invoke onPromptSelect exactly once.
         */
        it('each prompt button invokes onPromptSelect exactly once per click', () => {
            fc.assert(
                fc.property(fc.constant(true), () => {
                    const onPromptSelect = jest.fn();
                    const { container, unmount } = render(<EmptyState onPromptSelect={onPromptSelect} />);

                    const prompts = container.querySelectorAll('.empty-state__prompt');

                    prompts.forEach((prompt, index) => {
                        onPromptSelect.mockClear();
                        fireEvent.click(prompt);
                        expect(onPromptSelect).toHaveBeenCalledTimes(1);
                    });

                    unmount();
                }),
                { numRuns: 10 },
            );
        });

        /**
         * Validates: Accessibility
         * The prompts container SHALL have proper ARIA attributes.
         */
        it('prompts container has proper ARIA attributes', () => {
            fc.assert(
                fc.property(fc.constant(true), () => {
                    const onPromptSelect = jest.fn();
                    const { container, unmount } = render(<EmptyState onPromptSelect={onPromptSelect} />);

                    const promptsContainer = container.querySelector('.empty-state__prompts');
                    expect(promptsContainer).not.toBeNull();
                    expect(promptsContainer).toHaveAttribute('role', 'group');
                    expect(promptsContainer).toHaveAttribute('aria-label');

                    unmount();
                }),
                { numRuns: 10 },
            );
        });

        /**
         * Validates: Consistent rendering
         * The EmptyState SHALL render consistently across multiple renders.
         */
        it('renders consistently across multiple renders', () => {
            fc.assert(
                fc.property(fc.integer({ min: 1, max: 5 }), (renderCount) => {
                    const onPromptSelect = jest.fn();

                    for (let i = 0; i < renderCount; i++) {
                        const { container, unmount } = render(<EmptyState onPromptSelect={onPromptSelect} />);

                        expect(container.querySelector('.empty-state')).not.toBeNull();
                        expect(container.querySelector('.empty-state__title')).not.toBeNull();
                        expect(container.querySelector('.empty-state__description')).not.toBeNull();
                        expect(container.querySelectorAll('.empty-state__prompt').length).toBeGreaterThanOrEqual(1);

                        unmount();
                    }
                }),
                { numRuns: 10 },
            );
        });
    });
});
