"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AccessibilityChecker = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const AccessibilityChecker = ({ children, realTime = false, showDetails = true, targetSelector, onIssuesFound, }) => {
    const [issues, setIssues] = (0, react_1.useState)([]);
    const [isAnalyzing, setIsAnalyzing] = (0, react_1.useState)(false);
    const [score, setScore] = (0, react_1.useState)(100);
    const containerRef = (0, react_1.useRef)(null);
    // WCAG 2.1 AA compliance rules
    const wcagRules = [
        // 1.1.1 Non-text Content (Level A)
        {
            id: '1.1.1',
            level: 'A',
            category: 'perceivable',
            description: 'All images must have alternative text',
            check: (element) => {
                if (element.tagName === 'IMG') {
                    const img = element;
                    if (!img.alt && !img.getAttribute('aria-label') && !img.getAttribute('aria-labelledby')) {
                        return {
                            criterion: '1.1.1 Non-text Content',
                            message: 'Image missing alternative text',
                            severity: 'error',
                            element: element.outerHTML,
                            fix: 'Add alt attribute or aria-label to the image',
                            details: 'All images must have alternative text that serves the equivalent purpose of the visual content',
                        };
                    }
                }
                return null;
            },
        },
        // 1.3.1 Info and Relationships (Level A)
        {
            id: '1.3.1',
            level: 'A',
            category: 'perceivable',
            description: 'Information and relationships must be programmatically determinable',
            check: (element) => {
                // Check for form labels
                if (element.tagName === 'INPUT' || element.tagName === 'TEXTAREA' || element.tagName === 'SELECT') {
                    const input = element;
                    const hasLabel = document.querySelector(`label[for="${input.id}"]`) ||
                        input.getAttribute('aria-label') ||
                        input.getAttribute('aria-labelledby');
                    if (!hasLabel) {
                        return {
                            criterion: '1.3.1 Info and Relationships',
                            message: 'Form control missing label',
                            severity: 'error',
                            element: element.outerHTML,
                            fix: 'Add a label element or aria-label attribute',
                            details: 'All form controls must have accessible labels',
                        };
                    }
                }
                // Check for heading hierarchy
                if (element.tagName.match(/^H[1-6]$/)) {
                    const headingLevel = parseInt(element.tagName.charAt(1));
                    const prevHeading = element.previousElementSibling?.closest('[role="heading"], h1, h2, h3, h4, h5, h6');
                    if (prevHeading) {
                        const prevLevel = prevHeading.tagName.match(/^H([1-6])$/)
                            ? parseInt(prevHeading.tagName.charAt(1))
                            : parseInt(prevHeading.getAttribute('aria-level') || '1');
                        if (headingLevel > prevLevel + 1) {
                            return {
                                criterion: '1.3.1 Info and Relationships',
                                message: 'Heading levels should not skip',
                                severity: 'warning',
                                element: element.outerHTML,
                                fix: `Use h${prevLevel + 1} instead of h${headingLevel}`,
                                details: 'Heading levels should increase by one and not skip levels',
                            };
                        }
                    }
                }
                return null;
            },
        },
        // 1.4.3 Contrast (Level AA)
        {
            id: '1.4.3',
            level: 'AA',
            category: 'perceivable',
            description: 'Text must have sufficient contrast ratio',
            check: (element) => {
                const computedStyle = window.getComputedStyle(element);
                const fontSize = parseFloat(computedStyle.fontSize);
                const fontWeight = computedStyle.fontWeight;
                // Large text is 18pt+ (24px+) or 14pt+ (18.66px+) and bold
                const isLargeText = fontSize >= 24 || (fontSize >= 18.66 && (fontWeight === 'bold' || parseInt(fontWeight) >= 700));
                // This is a simplified check - in a real implementation, you'd calculate actual contrast
                const textColor = computedStyle.color;
                const backgroundColor = computedStyle.backgroundColor;
                if (textColor && backgroundColor && textColor !== 'inherit' && backgroundColor !== 'inherit') {
                    // Simplified contrast check (would need proper color parsing in production)
                    const hasText = element.textContent?.trim();
                    if (hasText && (textColor === backgroundColor || textColor.includes('rgb(128') || backgroundColor.includes('rgb(128'))) {
                        return {
                            criterion: '1.4.3 Contrast (Minimum)',
                            message: 'Insufficient color contrast',
                            severity: 'error',
                            element: element.outerHTML,
                            fix: 'Increase color contrast between text and background',
                            details: `Text requires ${isLargeText ? '3:1' : '4.5:1'} contrast ratio for WCAG AA compliance`,
                        };
                    }
                }
                return null;
            },
        },
        // 2.1.1 Keyboard (Level A)
        {
            id: '2.1.1',
            level: 'A',
            category: 'operable',
            description: 'All functionality must be available via keyboard',
            check: (element) => {
                const interactiveElements = ['BUTTON', 'A', 'INPUT', 'TEXTAREA', 'SELECT'];
                const hasClickHandler = element.getAttribute('onclick') || element.addEventListener;
                if (hasClickHandler && !interactiveElements.includes(element.tagName)) {
                    const tabIndex = element.getAttribute('tabindex');
                    const role = element.getAttribute('role');
                    if (tabIndex === null && !['button', 'link', 'menuitem'].includes(role || '')) {
                        return {
                            criterion: '2.1.1 Keyboard',
                            message: 'Interactive element not keyboard accessible',
                            severity: 'error',
                            element: element.outerHTML,
                            fix: 'Add tabindex="0" and appropriate role, or use semantic HTML',
                            details: 'All interactive elements must be keyboard accessible',
                        };
                    }
                }
                return null;
            },
        },
        // 2.4.3 Focus Order (Level A)
        {
            id: '2.4.3',
            level: 'A',
            category: 'operable',
            description: 'Focus order must be logical',
            check: (element) => {
                const tabIndex = element.getAttribute('tabindex');
                if (tabIndex && parseInt(tabIndex) > 0) {
                    return {
                        criterion: '2.4.3 Focus Order',
                        message: 'Avoid positive tabindex values',
                        severity: 'warning',
                        element: element.outerHTML,
                        fix: 'Use tabindex="0" or rely on natural DOM order',
                        details: 'Positive tabindex values can create confusing focus order',
                    };
                }
                return null;
            },
        },
        // 2.4.6 Headings and Labels (Level AA)
        {
            id: '2.4.6',
            level: 'AA',
            category: 'operable',
            description: 'Headings and labels must be descriptive',
            check: (element) => {
                if (element.tagName.match(/^H[1-6]$/)) {
                    const text = element.textContent?.trim();
                    if (!text || text.length < 3) {
                        return {
                            criterion: '2.4.6 Headings and Labels',
                            message: 'Heading text too short or empty',
                            severity: 'warning',
                            element: element.outerHTML,
                            fix: 'Provide descriptive heading text',
                            details: 'Headings should clearly describe the content that follows',
                        };
                    }
                }
                if (element.tagName === 'LABEL') {
                    const text = element.textContent?.trim();
                    if (!text || text.length < 2) {
                        return {
                            criterion: '2.4.6 Headings and Labels',
                            message: 'Label text too short or empty',
                            severity: 'error',
                            element: element.outerHTML,
                            fix: 'Provide descriptive label text',
                            details: 'Labels should clearly describe the purpose of form controls',
                        };
                    }
                }
                return null;
            },
        },
        // 4.1.2 Name, Role, Value (Level A)
        {
            id: '4.1.2',
            level: 'A',
            category: 'robust',
            description: 'UI components must have accessible name, role, and value',
            check: (element) => {
                const interactiveRoles = ['button', 'link', 'checkbox', 'radio', 'textbox', 'combobox', 'listbox'];
                const role = element.getAttribute('role');
                if (interactiveRoles.includes(role || '')) {
                    const hasAccessibleName = element.getAttribute('aria-label') ||
                        element.getAttribute('aria-labelledby') ||
                        element.textContent?.trim();
                    if (!hasAccessibleName) {
                        return {
                            criterion: '4.1.2 Name, Role, Value',
                            message: 'Interactive element missing accessible name',
                            severity: 'error',
                            element: element.outerHTML,
                            fix: 'Add aria-label, aria-labelledby, or text content',
                            details: 'All interactive elements must have an accessible name',
                        };
                    }
                }
                return null;
            },
        },
    ];
    const analyzeElement = (element) => {
        const elementIssues = [];
        wcagRules.forEach(rule => {
            const issue = rule.check(element);
            if (issue) {
                elementIssues.push(issue);
            }
        });
        return elementIssues;
    };
    const analyzeAccessibility = async () => {
        if (!containerRef.current)
            return;
        setIsAnalyzing(true);
        const allIssues = [];
        try {
            // Get target elements
            const targetElement = targetSelector
                ? containerRef.current.querySelector(targetSelector)
                : containerRef.current;
            if (!targetElement)
                return;
            // Analyze the target element and all descendants
            const elementsToCheck = [targetElement, ...Array.from(targetElement.querySelectorAll('*'))];
            elementsToCheck.forEach(element => {
                const issues = analyzeElement(element);
                allIssues.push(...issues);
            });
            // Calculate accessibility score
            const errorCount = allIssues.filter(issue => issue.severity === 'error').length;
            const warningCount = allIssues.filter(issue => issue.severity === 'warning').length;
            const calculatedScore = Math.max(0, 100 - (errorCount * 10) - (warningCount * 5));
            setIssues(allIssues);
            setScore(calculatedScore);
            onIssuesFound?.(allIssues);
        }
        catch (error) {
            console.error('Accessibility analysis failed:', error);
        }
        finally {
            setIsAnalyzing(false);
        }
    };
    (0, react_1.useEffect)(() => {
        if (realTime) {
            const timeoutId = setTimeout(analyzeAccessibility, 500);
            return () => clearTimeout(timeoutId);
        }
        return undefined;
    }, [children, realTime, targetSelector]);
    const getScoreColor = (score) => {
        if (score >= 90)
            return '#10b981'; // Green
        if (score >= 70)
            return '#f59e0b'; // Yellow
        return '#ef4444'; // Red
    };
    const getScoreLabel = (score) => {
        if (score >= 90)
            return 'Excellent';
        if (score >= 70)
            return 'Good';
        if (score >= 50)
            return 'Fair';
        return 'Poor';
    };
    return ((0, jsx_runtime_1.jsxs)("div", { className: "accessibility-checker", children: [(0, jsx_runtime_1.jsx)("div", { ref: containerRef, className: "accessibility-target", children: children }), showDetails && ((0, jsx_runtime_1.jsxs)("div", { className: "accessibility-report", style: { marginTop: '1rem', padding: '1rem', border: '1px solid #e5e7eb', borderRadius: '0.5rem' }, children: [(0, jsx_runtime_1.jsxs)("div", { className: "score-section", style: { display: 'flex', alignItems: 'center', gap: '1rem', marginBottom: '1rem' }, children: [(0, jsx_runtime_1.jsxs)("div", { className: "score-circle", style: {
                                    width: '60px',
                                    height: '60px',
                                    borderRadius: '50%',
                                    backgroundColor: getScoreColor(score),
                                    color: 'white',
                                    display: 'flex',
                                    alignItems: 'center',
                                    justifyContent: 'center',
                                    fontSize: '18px',
                                    fontWeight: 'bold',
                                }, children: [score, "%"] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("h3", { style: { margin: 0, fontSize: '1.25rem' }, children: ["Accessibility Score: ", getScoreLabel(score)] }), (0, jsx_runtime_1.jsxs)("p", { style: { margin: 0, color: '#6b7280' }, children: [issues.length, " issues found"] })] }), (0, jsx_runtime_1.jsx)("button", { onClick: analyzeAccessibility, disabled: isAnalyzing, style: {
                                    marginLeft: 'auto',
                                    padding: '0.5rem 1rem',
                                    backgroundColor: '#3b82f6',
                                    color: 'white',
                                    border: 'none',
                                    borderRadius: '0.375rem',
                                    cursor: isAnalyzing ? 'not-allowed' : 'pointer',
                                    opacity: isAnalyzing ? 0.6 : 1,
                                }, children: isAnalyzing ? 'Analyzing...' : 'Re-analyze' })] }), issues.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "issues-section", children: [(0, jsx_runtime_1.jsx)("h4", { style: { marginBottom: '0.5rem' }, children: "Issues Found:" }), (0, jsx_runtime_1.jsx)("div", { style: { maxHeight: '400px', overflowY: 'auto' }, children: issues.map((issue, index) => ((0, jsx_runtime_1.jsx)("div", { style: {
                                        padding: '0.75rem',
                                        marginBottom: '0.5rem',
                                        borderLeft: `4px solid ${issue.severity === 'error' ? '#ef4444' :
                                            issue.severity === 'warning' ? '#f59e0b' : '#6b7280'}`,
                                        backgroundColor: '#f9fafb',
                                        borderRadius: '0.375rem',
                                    }, children: (0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }, children: [(0, jsx_runtime_1.jsxs)("div", { style: { flex: 1 }, children: [(0, jsx_runtime_1.jsx)("h5", { style: { margin: 0, fontSize: '1rem', color: '#1f2937' }, children: issue.criterion }), (0, jsx_runtime_1.jsx)("p", { style: { margin: '0.25rem 0', color: '#6b7280' }, children: issue.message }), issue.details && ((0, jsx_runtime_1.jsx)("p", { style: { margin: '0.25rem 0', fontSize: '0.875rem', color: '#4b5563' }, children: issue.details })), issue.fix && ((0, jsx_runtime_1.jsxs)("div", { style: { marginTop: '0.5rem', padding: '0.5rem', backgroundColor: '#ecfdf5', borderRadius: '0.25rem' }, children: [(0, jsx_runtime_1.jsx)("strong", { style: { color: '#065f46' }, children: "Fix: " }), (0, jsx_runtime_1.jsx)("span", { style: { color: '#047857' }, children: issue.fix })] }))] }), (0, jsx_runtime_1.jsx)("span", { style: {
                                                    padding: '0.25rem 0.5rem',
                                                    fontSize: '0.75rem',
                                                    fontWeight: 'bold',
                                                    borderRadius: '0.25rem',
                                                    backgroundColor: issue.severity === 'error' ? '#fef2f2' :
                                                        issue.severity === 'warning' ? '#fffbeb' : '#f3f4f6',
                                                    color: issue.severity === 'error' ? '#dc2626' :
                                                        issue.severity === 'warning' ? '#d97706' : '#6b7280',
                                                }, children: issue.severity.toUpperCase() })] }) }, index))) })] })), issues.length === 0 && !isAnalyzing && ((0, jsx_runtime_1.jsxs)("div", { style: { textAlign: 'center', padding: '2rem', color: '#10b981' }, children: [(0, jsx_runtime_1.jsx)("strong", { children: "\uD83C\uDF89 No accessibility issues found!" }), (0, jsx_runtime_1.jsx)("p", { style: { margin: '0.5rem 0 0 0', color: '#6b7280' }, children: "This component meets WCAG 2.1 AA standards." })] }))] }))] }));
};
exports.AccessibilityChecker = AccessibilityChecker;
exports.default = exports.AccessibilityChecker;
//# sourceMappingURL=AccessibilityChecker.js.map