// @vitest-environment jsdom
import { render, fireEvent, act } from '@testing-library/react';
import { FancyCursor } from './FancyCursor';
import { describe, it, expect, vi, beforeAll, afterAll, beforeEach } from 'vitest';
import React from 'react';

describe('FancyCursor', () => {
    beforeAll(() => {
        // Mock elementFromPoint for JSDOM
        // @ts-ignore
        document.elementFromPoint = vi.fn((x, y) => null);

        // Mock requestAnimationFrame
        vi.useFakeTimers();
    });

    afterAll(() => {
        vi.useRealTimers();
        // @ts-ignore
        delete document.elementFromPoint;
    });

    beforeEach(() => {
        vi.clearAllMocks();

        // Ensure we are not seen as a touch device
        Object.defineProperty(navigator, 'maxTouchPoints', { value: 0, writable: true });
        // @ts-ignore
        delete window.ontouchstart;
        // console.log('Test Setup:', { ontouchstart: 'ontouchstart' in window, maxTouchPoints: navigator.maxTouchPoints });
    });

    it('renders and updates position on mousemove', () => {
        const { container } = render(<FancyCursor />);
        // Using firstElementChild because querySelector seems flaky in this test environment
        const cursor = container.firstElementChild as HTMLElement;
        expect(cursor).toBeTruthy();
        expect(cursor.id).toBe('fancy-cursor');

        fireEvent.mouseMove(window, { clientX: 100, clientY: 100 });

        act(() => {
            vi.runAllTimers();
        });

        // Check transform
        expect(cursor.style.transform).toContain('translate3d(100px, 100px, 0)');
    });

    it('toggles link-hover class when hovering a link', () => {
        // We need to attach the link to the document body because FancyCursor uses global event listeners
        // and checks the document structure via events or elementFromPoint.
        const link = document.createElement('a');
        link.href = '#';
        link.id = 'test-link';
        link.textContent = 'Link';
        document.body.appendChild(link);

        const { container } = render(<FancyCursor />);
        const cursor = container.firstElementChild as HTMLElement;
        expect(cursor).toBeTruthy();

        // Simulate mouse over the link.
        // Important: in our optimized code, we rely on 'mouseover' event to set 'hoveredElement'.
        fireEvent.mouseOver(link);

        // Then mouseMove triggers the update loop
        fireEvent.mouseMove(window, { clientX: 50, clientY: 50 });

        act(() => {
            vi.runAllTimers();
        });

        expect(cursor.classList.contains('link-hover')).toBe(true);

        // Move away to body
        fireEvent.mouseOver(document.body);
        fireEvent.mouseMove(window, { clientX: 200, clientY: 200 });

        act(() => {
            vi.runAllTimers();
        });

        expect(cursor.classList.contains('link-hover')).toBe(false);

        document.body.removeChild(link);
    });

    it('does not call elementFromPoint on mousemove', () => {
        // Reset elementFromPoint mock
        const mockElementFromPoint = vi.fn();
        // @ts-ignore
        document.elementFromPoint = mockElementFromPoint;

        render(<FancyCursor />);

        // Trigger mousemove
        fireEvent.mouseMove(window, { clientX: 10, clientY: 10 });

        act(() => {
            vi.runAllTimers();
        });

        // Should NOT be called in the optimized version
        expect(mockElementFromPoint).not.toHaveBeenCalled();
    });
});
