/**
 * JEST TEST TEMPLATE FOR LWC
 *
 * This template demonstrates Jest testing patterns for LWC:
 * - Component rendering
 * - Wire service mocking
 * - Apex method mocking
 * - Event handling
 * - DOM queries
 * - Async testing
 *
 * This file ships with a .example suffix so Jest does not auto-discover it
 * inside installed skill folders. Copy it into your project and rename it to:
 * force-app/main/default/lwc/<yourComponent>/__tests__/<yourComponent>.test.js
 *
 * Replace: componentName → yourComponentName
 * Replace: ComponentName → YourComponentName
 */

import { createElement } from 'lwc';
import ComponentName from 'c/componentName';

// Mock Apex methods
import getRecords from '@salesforce/apex/ComponentController.getRecords';
import saveRecord from '@salesforce/apex/ComponentController.saveRecord';

// Mock wire adapters
import { getRecord } from 'lightning/uiRecordApi';

// ═══════════════════════════════════════════════════════════════════════════
// MOCK SETUP
// ═══════════════════════════════════════════════════════════════════════════

// Mock Apex methods
jest.mock(
    '@salesforce/apex/ComponentController.getRecords',
    () => ({ default: jest.fn() }),
    { virtual: true }
);

jest.mock(
    '@salesforce/apex/ComponentController.saveRecord',
    () => ({ default: jest.fn() }),
    { virtual: true }
);

// ═══════════════════════════════════════════════════════════════════════════
// TEST DATA
// ═══════════════════════════════════════════════════════════════════════════

const MOCK_RECORDS = [
    { Id: '001xx000003DGFAAA4', Name: 'Test Account 1', Industry: 'Technology' },
    { Id: '001xx000003DGFBBB4', Name: 'Test Account 2', Industry: 'Finance' },
    { Id: '001xx000003DGFCCC4', Name: 'Test Account 3', Industry: 'Healthcare' }
];

const MOCK_RECORD = {
    Id: '001xx000003DGFAAA4',
    Name: { value: 'Test Account' },
    Industry: { value: 'Technology' },
    Phone: { value: '555-1234' }
};

const MOCK_ERROR = {
    body: { message: 'An error occurred' },
    ok: false,
    status: 500,
    statusText: 'Internal Server Error'
};

// ═══════════════════════════════════════════════════════════════════════════
// HELPER FUNCTIONS
// ═══════════════════════════════════════════════════════════════════════════

/**
 * Flush all pending promises in the event queue
 */
const flushPromises = () => new Promise(resolve => setTimeout(resolve, 0));

/**
 * Create component with optional public properties
 */
function createComponent(props = {}) {
    const element = createElement('c-component-name', { is: ComponentName });

    // Set public properties
    Object.keys(props).forEach(key => {
        element[key] = props[key];
    });

    document.body.appendChild(element);
    return element;
}

// ═══════════════════════════════════════════════════════════════════════════
// TEST SUITE
// ═══════════════════════════════════════════════════════════════════════════

describe('c-component-name', () => {
    // Reset DOM and mocks after each test
    afterEach(() => {
        // Remove all created elements
        while (document.body.firstChild) {
            document.body.removeChild(document.body.firstChild);
        }
        // Reset all mocks
        jest.clearAllMocks();
    });

    // ═══════════════════════════════════════════════════════════════════════
    // RENDERING TESTS
    // ═══════════════════════════════════════════════════════════════════════

    describe('rendering', () => {
        it('renders component with default state', () => {
            const element = createComponent();

            // Check component is rendered
            const card = element.shadowRoot.querySelector('lightning-card');
            expect(card).not.toBeNull();
        });

        it('renders with custom title property', () => {
            const element = createComponent({ title: 'Custom Title' });

            const card = element.shadowRoot.querySelector('lightning-card');
            expect(card.title).toBe('Custom Title');
        });

        it('displays loading spinner initially', () => {
            const element = createComponent();

            const spinner = element.shadowRoot.querySelector('lightning-spinner');
            expect(spinner).not.toBeNull();
        });
    });

    // ═══════════════════════════════════════════════════════════════════════
    // DATA FETCHING TESTS
    // ═══════════════════════════════════════════════════════════════════════

    describe('data fetching', () => {
        it('displays records when data is returned', async () => {
            // Setup mock response
            getRecords.mockResolvedValue(MOCK_RECORDS);

            const element = createComponent({ recordId: '001xx000000000' });

            // Wait for async operations
            await flushPromises();

            // Check records are displayed
            const items = element.shadowRoot.querySelectorAll('.record-item');
            expect(items.length).toBe(3);
        });

        it('displays error message when fetch fails', async () => {
            // Setup mock error
            getRecords.mockRejectedValue(MOCK_ERROR);

            const element = createComponent({ recordId: '001xx000000000' });

            await flushPromises();

            // Check error is displayed
            const error = element.shadowRoot.querySelector('.error-message');
            expect(error).not.toBeNull();
            expect(error.textContent).toContain('An error occurred');
        });

        it('displays empty state when no records returned', async () => {
            getRecords.mockResolvedValue([]);

            const element = createComponent({ recordId: '001xx000000000' });

            await flushPromises();

            const emptyState = element.shadowRoot.querySelector('.empty-state');
            expect(emptyState).not.toBeNull();
        });
    });

    // ═══════════════════════════════════════════════════════════════════════
    // WIRE SERVICE TESTS
    // ═══════════════════════════════════════════════════════════════════════

    describe('wire service', () => {
        it('fetches record data via wire adapter', async () => {
            const element = createComponent({ recordId: '001xx000000000' });

            // Emit wire data
            getRecord.emit(MOCK_RECORD);

            await flushPromises();

            // Verify data is displayed
            const nameField = element.shadowRoot.querySelector('.account-name');
            expect(nameField.textContent).toBe('Test Account');
        });

        it('handles wire adapter error', async () => {
            const element = createComponent({ recordId: '001xx000000000' });

            // Emit error
            getRecord.error(MOCK_ERROR);

            await flushPromises();

            const error = element.shadowRoot.querySelector('.error-message');
            expect(error).not.toBeNull();
        });
    });

    // ═══════════════════════════════════════════════════════════════════════
    // EVENT HANDLING TESTS
    // ═══════════════════════════════════════════════════════════════════════

    describe('event handling', () => {
        it('dispatches recordselected event on row click', async () => {
            getRecords.mockResolvedValue(MOCK_RECORDS);

            const element = createComponent({ recordId: '001xx000000000' });
            await flushPromises();

            // Create event handler mock
            const handler = jest.fn();
            element.addEventListener('recordselected', handler);

            // Click on first record
            const firstRow = element.shadowRoot.querySelector('.record-item');
            firstRow.click();

            // Verify event was dispatched
            expect(handler).toHaveBeenCalled();
            expect(handler.mock.calls[0][0].detail).toEqual({
                recordId: '001xx000003DGFAAA4',
                recordName: 'Test Account 1'
            });
        });

        it('handles refresh button click', async () => {
            getRecords.mockResolvedValue(MOCK_RECORDS);

            const element = createComponent({ recordId: '001xx000000000' });
            await flushPromises();

            // Clear mock to track new calls
            getRecords.mockClear();

            // Click refresh
            const refreshButton = element.shadowRoot.querySelector('lightning-button-icon[icon-name="utility:refresh"]');
            refreshButton.click();

            await flushPromises();

            // Verify data was re-fetched
            expect(getRecords).toHaveBeenCalled();
        });
    });

    // ═══════════════════════════════════════════════════════════════════════
    // FORM SUBMISSION TESTS
    // ═══════════════════════════════════════════════════════════════════════

    describe('form submission', () => {
        it('saves record successfully', async () => {
            saveRecord.mockResolvedValue({ Id: '001xx000000NEW', Name: 'New Account' });

            const element = createComponent();
            await flushPromises();

            // Fill form fields
            const nameInput = element.shadowRoot.querySelector('lightning-input[name="Name"]');
            nameInput.value = 'New Account';
            nameInput.dispatchEvent(new CustomEvent('change'));

            // Submit form
            const submitButton = element.shadowRoot.querySelector('lightning-button[type="submit"]');
            submitButton.click();

            await flushPromises();

            // Verify save was called
            expect(saveRecord).toHaveBeenCalledWith({
                record: expect.objectContaining({ Name: 'New Account' })
            });
        });

        it('displays validation error for required fields', async () => {
            const element = createComponent();
            await flushPromises();

            // Submit without filling required fields
            const submitButton = element.shadowRoot.querySelector('lightning-button[type="submit"]');
            submitButton.click();

            await flushPromises();

            // Check validation message
            const input = element.shadowRoot.querySelector('lightning-input[required]');
            expect(input.reportValidity).toHaveBeenCalled;
        });
    });

    // ═══════════════════════════════════════════════════════════════════════
    // ACCESSIBILITY TESTS
    // ═══════════════════════════════════════════════════════════════════════

    describe('accessibility', () => {
        it('has accessible button labels', async () => {
            const element = createComponent();
            await flushPromises();

            const buttons = element.shadowRoot.querySelectorAll('lightning-button, lightning-button-icon');
            buttons.forEach(button => {
                // Each button should have label or alternative-text
                const hasLabel = button.label || button.alternativeText;
                expect(hasLabel).toBeTruthy();
            });
        });

        it('announces loading state to screen readers', async () => {
            const element = createComponent();

            const spinner = element.shadowRoot.querySelector('lightning-spinner');
            expect(spinner.alternativeText).toBe('Loading');
        });
    });

    // ═══════════════════════════════════════════════════════════════════════
    // EDGE CASES
    // ═══════════════════════════════════════════════════════════════════════

    describe('edge cases', () => {
        it('handles null recordId gracefully', async () => {
            const element = createComponent({ recordId: null });
            await flushPromises();

            // Should not crash
            expect(element).toBeTruthy();
        });

        it('handles special characters in data', async () => {
            const specialRecords = [
                { Id: '001xx000000001', Name: "Test's <Account> & \"Quotes\"" }
            ];
            getRecords.mockResolvedValue(specialRecords);

            const element = createComponent({ recordId: '001xx000000000' });
            await flushPromises();

            const name = element.shadowRoot.querySelector('.record-name');
            expect(name.textContent).toContain("Test's <Account>");
        });

        it('handles rapid successive updates', async () => {
            const element = createComponent();
            await flushPromises();

            // Simulate rapid changes
            for (let i = 0; i < 10; i++) {
                element.recordId = `001xx00000000${i}`;
            }

            await flushPromises();

            // Component should still be stable
            expect(element.shadowRoot.querySelector('lightning-card')).not.toBeNull();
        });
    });
});
