<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Best Practices — Cartographer</title>
    <style>
        *, *::before, *::after {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        body {
            font-family: 'Segoe UI', -apple-system, BlinkMacSystemFont, sans-serif;
            background: #f3f4f6;
            color: #1f2937;
            min-height: 100vh;
            display: flex;
            flex-direction: column;
        }

        /* ===== Header ===== */
        .page-header {
            background: #ffffff;
            border-bottom: 1px solid #e5e7eb;
            padding: 20px 24px;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
        }

        .header-top {
            display: flex;
            justify-content: space-between;
            align-items: flex-start;
            gap: 16px;
            flex-wrap: wrap;
        }

        .header-text h1 {
            font-size: 20px;
            font-weight: 700;
            color: #111827;
            margin-bottom: 4px;
        }

        .header-text p {
            font-size: 13px;
            color: #6b7280;
            line-height: 1.4;
        }

        .header-actions {
            display: flex;
            align-items: center;
            gap: 10px;
            flex-shrink: 0;
        }

        .header-actions select {
            font-family: inherit;
            font-size: 13px;
            padding: 7px 12px;
            border: 1px solid #d1d5db;
            border-radius: 6px;
            background: #ffffff;
            color: #1f2937;
            min-width: 200px;
            transition: border-color 0.15s, box-shadow 0.15s;
        }

        .header-actions select:focus {
            outline: none;
            border-color: #2563eb;
            box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.12);
        }

        /* ===== Buttons ===== */
        .btn {
            font-family: inherit;
            font-size: 13px;
            padding: 7px 16px;
            border-radius: 6px;
            border: 1px solid #d1d5db;
            background: #f9fafb;
            color: #374151;
            cursor: pointer;
            font-weight: 500;
            transition: background 0.15s, border-color 0.15s;
            white-space: nowrap;
        }

        .btn:hover {
            background: #f3f4f6;
            border-color: #9ca3af;
        }

        .btn:focus {
            outline: none;
            box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);
        }

        .btn:disabled {
            opacity: 0.5;
            cursor: not-allowed;
        }

        .btn-primary {
            background: #2563eb;
            color: #ffffff;
            border-color: #2563eb;
            font-weight: 600;
        }

        .btn-primary:hover:not(:disabled) {
            background: #1d4ed8;
        }

        .btn-sm {
            font-size: 12px;
            padding: 4px 10px;
        }

        .btn-resolve {
            background: #059669;
            color: #ffffff;
            border-color: #059669;
        }

        .btn-resolve:hover:not(:disabled) {
            background: #047857;
        }

        .btn-reopen {
            background: #f9fafb;
            color: #374151;
            border-color: #d1d5db;
        }

        /* ===== Tier Gate ===== */
        .tier-gate {
            display: none;
            flex: 1;
            justify-content: center;
            align-items: center;
            padding: 60px 24px;
        }

        .tier-gate.active {
            display: flex;
        }

        .tier-gate-card {
            text-align: center;
            background: #ffffff;
            border: 1px solid #e5e7eb;
            border-radius: 12px;
            padding: 48px 40px;
            max-width: 480px;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
        }

        .tier-gate-icon {
            font-size: 48px;
            margin-bottom: 16px;
            color: #d1d5db;
        }

        .tier-gate-card h2 {
            font-size: 18px;
            font-weight: 700;
            color: #111827;
            margin-bottom: 8px;
        }

        .tier-gate-card p {
            font-size: 14px;
            color: #6b7280;
            line-height: 1.5;
        }

        /* ===== Main Content ===== */
        .main-content {
            flex: 1;
            display: none;
            flex-direction: column;
            overflow-y: auto;
        }

        .main-content.active {
            display: flex;
        }

        /* ===== Summary Cards ===== */
        .summary-cards {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
            gap: 14px;
            padding: 20px 24px 0;
        }

        .summary-card {
            background: #ffffff;
            border: 1px solid #e5e7eb;
            border-radius: 10px;
            padding: 16px 20px;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
            position: relative;
            overflow: hidden;
        }

        .summary-card::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            height: 3px;
        }

        .summary-card.card-total::before { background: #6b7280; }
        .summary-card.card-critical::before { background: #dc2626; }
        .summary-card.card-warning::before { background: #f59e0b; }
        .summary-card.card-info::before { background: #2563eb; }
        .summary-card.card-resolved::before { background: #059669; }

        .summary-card-label {
            font-size: 11px;
            font-weight: 600;
            color: #6b7280;
            text-transform: uppercase;
            letter-spacing: 0.4px;
            margin-bottom: 6px;
        }

        .summary-card-value {
            font-size: 28px;
            font-weight: 700;
            color: #111827;
            line-height: 1;
        }

        .summary-card.card-critical .summary-card-value { color: #dc2626; }
        .summary-card.card-warning .summary-card-value { color: #f59e0b; }
        .summary-card.card-info .summary-card-value { color: #2563eb; }
        .summary-card.card-resolved .summary-card-value { color: #059669; }

        /* ===== Filter Bar ===== */
        .filter-bar {
            background: #ffffff;
            border: 1px solid #e5e7eb;
            border-radius: 10px;
            padding: 14px 20px;
            margin: 16px 24px 0;
            display: flex;
            flex-wrap: wrap;
            gap: 12px;
            align-items: flex-end;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
        }

        .filter-group {
            display: flex;
            flex-direction: column;
            gap: 3px;
        }

        .filter-group label {
            font-size: 11px;
            font-weight: 600;
            color: #6b7280;
            text-transform: uppercase;
            letter-spacing: 0.3px;
        }

        .filter-group select {
            font-family: inherit;
            font-size: 13px;
            padding: 6px 10px;
            border: 1px solid #d1d5db;
            border-radius: 6px;
            background: #ffffff;
            color: #1f2937;
            min-width: 160px;
            transition: border-color 0.15s, box-shadow 0.15s;
        }

        .filter-group select:focus {
            outline: none;
            border-color: #2563eb;
            box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.12);
        }

        /* Toggle switch */
        .toggle-group {
            display: flex;
            align-items: center;
            gap: 8px;
            padding-bottom: 2px;
        }

        .toggle-label {
            font-size: 13px;
            color: #374151;
            font-weight: 500;
            cursor: pointer;
        }

        .toggle-switch {
            position: relative;
            width: 36px;
            height: 20px;
            cursor: pointer;
        }

        .toggle-switch input {
            opacity: 0;
            width: 0;
            height: 0;
        }

        .toggle-slider {
            position: absolute;
            top: 0; left: 0; right: 0; bottom: 0;
            background: #d1d5db;
            border-radius: 10px;
            transition: background 0.2s;
        }

        .toggle-slider::before {
            content: '';
            position: absolute;
            width: 16px;
            height: 16px;
            left: 2px;
            bottom: 2px;
            background: #ffffff;
            border-radius: 50%;
            transition: transform 0.2s;
        }

        .toggle-switch input:checked + .toggle-slider {
            background: #2563eb;
        }

        .toggle-switch input:checked + .toggle-slider::before {
            transform: translateX(16px);
        }

        .filter-actions {
            display: flex;
            align-items: flex-end;
            gap: 8px;
            margin-left: auto;
        }

        .result-count {
            font-size: 13px;
            color: #6b7280;
            white-space: nowrap;
            padding-bottom: 4px;
        }

        /* ===== Issues List ===== */
        .issues-container {
            flex: 1;
            padding: 16px 24px 24px;
        }

        .issue-card {
            background: #ffffff;
            border: 1px solid #e5e7eb;
            border-radius: 10px;
            margin-bottom: 10px;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
            overflow: hidden;
            transition: box-shadow 0.15s;
        }

        .issue-card:hover {
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
        }

        .issue-card.resolved {
            opacity: 0.65;
        }

        .issue-main {
            display: flex;
            gap: 14px;
            padding: 16px 20px;
            align-items: flex-start;
        }

        .issue-severity {
            flex-shrink: 0;
            width: 4px;
            min-height: 60px;
            border-radius: 2px;
            align-self: stretch;
        }

        .severity-critical { background: #dc2626; }
        .severity-warning { background: #f59e0b; }
        .severity-info { background: #2563eb; }

        .issue-body {
            flex: 1;
            min-width: 0;
        }

        .issue-header {
            display: flex;
            align-items: center;
            gap: 8px;
            flex-wrap: wrap;
            margin-bottom: 4px;
        }

        .issue-title {
            font-size: 14px;
            font-weight: 600;
            color: #111827;
        }

        .issue-rule {
            font-size: 11px;
            font-weight: 600;
            color: #9ca3af;
            font-family: 'Consolas', 'Courier New', monospace;
        }

        .issue-subtitle {
            font-size: 12px;
            color: #6b7280;
            margin-bottom: 6px;
            display: flex;
            gap: 6px;
            flex-wrap: wrap;
            align-items: center;
        }

        .issue-description {
            font-size: 13px;
            color: #374151;
            line-height: 1.5;
            margin-bottom: 8px;
        }

        .issue-badges {
            display: flex;
            gap: 6px;
            flex-wrap: wrap;
            margin-bottom: 8px;
        }

        /* Badges */
        .badge {
            display: inline-block;
            padding: 2px 8px;
            border-radius: 12px;
            font-size: 11px;
            font-weight: 600;
            white-space: nowrap;
        }

        .badge-critical {
            background: #fee2e2;
            color: #991b1b;
        }

        .badge-warning {
            background: #fef3c7;
            color: #92400e;
        }

        .badge-info {
            background: #dbeafe;
            color: #1e40af;
        }

        .badge-resolved {
            background: #d1fae5;
            color: #065f46;
        }

        .badge-category {
            background: #f3f4f6;
            color: #374151;
            font-weight: 500;
        }

        .badge-component {
            background: #e0e7ff;
            color: #3730a3;
            font-weight: 500;
        }

        .badge-dot {
            color: #d1d5db;
            font-weight: 400;
        }

        /* Expandable Sections */
        .expandable-sections {
            display: flex;
            gap: 8px;
            flex-wrap: wrap;
        }

        .expandable-toggle {
            font-family: inherit;
            font-size: 12px;
            font-weight: 600;
            color: #2563eb;
            background: none;
            border: none;
            cursor: pointer;
            padding: 2px 0;
            display: flex;
            align-items: center;
            gap: 4px;
        }

        .expandable-toggle:hover {
            color: #1d4ed8;
        }

        .expandable-toggle .arrow {
            font-size: 10px;
            transition: transform 0.2s;
        }

        .expandable-toggle.open .arrow {
            transform: rotate(90deg);
        }

        .expandable-content {
            display: none;
            padding: 12px 0 4px;
        }

        .expandable-content.open {
            display: block;
        }

        .expandable-content.recommendation {
            font-size: 13px;
            color: #374151;
            line-height: 1.5;
            background: #f0fdf4;
            border: 1px solid #bbf7d0;
            border-radius: 8px;
            padding: 12px 16px;
            margin-top: 8px;
        }

        .expandable-content.details {
            font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
            font-size: 12px;
            line-height: 1.5;
            color: #374151;
            background: #f9fafb;
            border: 1px solid #e5e7eb;
            border-radius: 8px;
            padding: 12px 16px;
            margin-top: 8px;
            max-height: 300px;
            overflow-y: auto;
            white-space: pre-wrap;
            word-break: break-all;
        }

        .issue-actions {
            display: flex;
            justify-content: flex-end;
            padding: 0 20px 12px;
        }

        /* ===== Toast ===== */
        .toast-container {
            position: fixed;
            bottom: 24px;
            right: 24px;
            z-index: 2000;
            display: flex;
            flex-direction: column;
            gap: 8px;
        }

        .toast {
            background: #1f2937;
            color: #ffffff;
            padding: 12px 20px;
            border-radius: 8px;
            font-size: 13px;
            font-weight: 500;
            box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
            animation: toastIn 0.25s ease;
            max-width: 420px;
        }

        .toast.success {
            background: #059669;
        }

        .toast.error {
            background: #dc2626;
        }

        @keyframes toastIn {
            from { opacity: 0; transform: translateY(12px); }
            to { opacity: 1; transform: translateY(0); }
        }

        /* ===== Spinner ===== */
        .spinner {
            display: inline-block;
            width: 18px;
            height: 18px;
            border: 2px solid #e5e7eb;
            border-top-color: #2563eb;
            border-radius: 50%;
            animation: spin 0.7s linear infinite;
            vertical-align: middle;
            margin-right: 6px;
        }

        .spinner-sm {
            width: 14px;
            height: 14px;
            border-width: 2px;
            margin-right: 4px;
        }

        @keyframes spin {
            to { transform: rotate(360deg); }
        }

        /* ===== Loading / Empty States ===== */
        .loading-state, .empty-state {
            text-align: center;
            padding: 60px 24px;
        }

        .empty-state-icon {
            font-size: 40px;
            color: #d1d5db;
            margin-bottom: 12px;
        }

        .empty-state h3 {
            font-size: 16px;
            color: #6b7280;
            font-weight: 600;
            margin-bottom: 6px;
        }

        .empty-state p {
            font-size: 13px;
            color: #9ca3af;
        }

        .loading-state {
            color: #6b7280;
            font-size: 14px;
        }

        /* ===== Error Banner ===== */
        .error-banner {
            background: #fef2f2;
            border: 1px solid #fecaca;
            color: #991b1b;
            padding: 10px 16px;
            font-size: 13px;
            border-radius: 8px;
            margin: 12px 24px 0;
            display: none;
        }

        /* ===== Analysis overlay ===== */
        .analysis-overlay {
            display: none;
            position: fixed;
            top: 0; left: 0; right: 0; bottom: 0;
            background: rgba(0, 0, 0, 0.4);
            z-index: 1500;
            justify-content: center;
            align-items: center;
        }

        .analysis-overlay.active {
            display: flex;
        }

        .analysis-dialog {
            background: #ffffff;
            border-radius: 12px;
            padding: 32px 40px;
            text-align: center;
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
            max-width: 400px;
        }

        .analysis-dialog h3 {
            font-size: 16px;
            font-weight: 700;
            color: #111827;
            margin-top: 12px;
            margin-bottom: 8px;
        }

        .analysis-dialog p {
            font-size: 13px;
            color: #6b7280;
        }

        .analysis-spinner {
            width: 40px;
            height: 40px;
            border: 3px solid #e5e7eb;
            border-top-color: #2563eb;
            border-radius: 50%;
            animation: spin 0.8s linear infinite;
            margin: 0 auto;
        }

        /* ===== Responsive ===== */
        @media (max-width: 768px) {
            .page-header {
                padding: 16px;
            }

            .header-top {
                flex-direction: column;
            }

            .header-actions {
                width: 100%;
            }

            .header-actions select {
                flex: 1;
                min-width: 0;
            }

            .summary-cards {
                grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
                padding: 16px 16px 0;
                gap: 10px;
            }

            .summary-card {
                padding: 12px 16px;
            }

            .summary-card-value {
                font-size: 24px;
            }

            .filter-bar {
                margin: 12px 16px 0;
                padding: 12px 16px;
            }

            .filter-group select {
                min-width: 120px;
            }

            .issues-container {
                padding: 12px 16px 16px;
            }

            .issue-main {
                padding: 12px 16px;
            }
        }
    </style>
</head>
<body>
    <!-- Header -->
    <div class="page-header">
        <div class="header-top">
            <div class="header-text">
                <h1>Best Practices</h1>
                <p>Analyze your solutions for deprecated features, poor naming, missing error handling, and more.</p>
            </div>
            <div class="header-actions">
                <select id="analysisSolutionPicker" disabled>
                    <option value="">Select a solution...</option>
                </select>
                <button class="btn btn-primary" id="btnRunAnalysis" disabled>Run Analysis</button>
            </div>
        </div>
    </div>

    <!-- Tier Gate -->
    <div class="tier-gate" id="tierGate">
        <div class="tier-gate-card">
            <div class="tier-gate-icon">&#128274;</div>
            <h2>Enterprise Feature</h2>
            <p>Best Practice Analysis is available on the Enterprise plan. Upgrade to unlock automated analysis of deprecated features, naming conventions, error handling, and more.</p>
            <a href="https://www.verseblocks.com/pricing" target="_blank" style="display:inline-block;margin-top:20px;padding:10px 24px;background:#2563eb;color:white;border-radius:8px;text-decoration:none;font-size:14px;font-weight:600;">View Plans &amp; Upgrade</a>
        </div>
    </div>

    <!-- Error Banner -->
    <div id="errorBanner" class="error-banner"></div>

    <!-- Main Content (hidden until tier check passes) -->
    <div class="main-content" id="mainContent">
        <!-- Summary Cards -->
        <div class="summary-cards" id="summaryCards">
            <div class="summary-card card-total">
                <div class="summary-card-label">Total Issues</div>
                <div class="summary-card-value" id="countTotal">--</div>
            </div>
            <div class="summary-card card-critical">
                <div class="summary-card-label">Critical</div>
                <div class="summary-card-value" id="countCritical">--</div>
            </div>
            <div class="summary-card card-warning">
                <div class="summary-card-label">Warnings</div>
                <div class="summary-card-value" id="countWarning">--</div>
            </div>
            <div class="summary-card card-info">
                <div class="summary-card-label">Info</div>
                <div class="summary-card-value" id="countInfo">--</div>
            </div>
            <div class="summary-card card-resolved">
                <div class="summary-card-label">Resolved</div>
                <div class="summary-card-value" id="countResolved">--</div>
            </div>
        </div>

        <!-- Filters -->
        <div class="filter-bar">
            <div class="filter-group">
                <label for="filterSolution">Solution</label>
                <select id="filterSolution">
                    <option value="">All Solutions</option>
                </select>
            </div>
            <div class="filter-group">
                <label for="filterSeverity">Severity</label>
                <select id="filterSeverity">
                    <option value="">All</option>
                    <option value="10001000">Critical</option>
                    <option value="10001001">Warning</option>
                    <option value="10001002">Info</option>
                </select>
            </div>
            <div class="filter-group">
                <label for="filterCategory">Category</label>
                <select id="filterCategory">
                    <option value="">All</option>
                    <option value="10001000">Deprecated Feature</option>
                    <option value="10001001">Unsupported Code</option>
                    <option value="10001002">Naming Convention</option>
                    <option value="10001003">Error Handling</option>
                    <option value="10001004">Performance</option>
                    <option value="10001005">Security</option>
                    <option value="10001006">Maintainability</option>
                    <option value="10001007">Configuration</option>
                </select>
            </div>
            <div class="toggle-group">
                <label class="toggle-switch" for="toggleResolved">
                    <input type="checkbox" id="toggleResolved" />
                    <span class="toggle-slider"></span>
                </label>
                <span class="toggle-label" for="toggleResolved">Show Resolved</span>
            </div>
            <div class="filter-actions">
                <span class="result-count" id="resultCount"></span>
                <button class="btn" id="btnResetFilters">Reset</button>
            </div>
        </div>

        <!-- Issues List -->
        <div class="issues-container" id="issuesContainer">
            <div class="loading-state" id="loadingState">
                <span class="spinner"></span> Loading issues...
            </div>
        </div>
    </div>

    <!-- Analysis Overlay -->
    <div class="analysis-overlay" id="analysisOverlay">
        <div class="analysis-dialog">
            <div class="analysis-spinner"></div>
            <h3>Analyzing Solution</h3>
            <p>Running best practice checks. This may take a moment...</p>
        </div>
    </div>

    <!-- Toast Container -->
    <div class="toast-container" id="toastContainer"></div>

    <script>
        // Analytics - fire and forget
        function vbAnalytics(eventType, details) {
            try {
                fetch('/api/data/v9.2/vb_configurations?$select=vb_license_key,vb_org_id&$top=1', {
                    headers: { 'Accept': 'application/json', 'OData-MaxVersion': '4.0', 'OData-Version': '4.0' },
                    credentials: 'include'
                }).then(function(r) { return r.json(); }).then(function(d) {
                    if (!d.value || !d.value[0]) return;
                    var c = d.value[0];
                    fetch('https://cartographer-api.azurewebsites.net/api/analytics/event', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({
                            licenseKey: c.vb_license_key,
                            orgId: c.vb_org_id || '',
                            eventType: eventType,
                            details: JSON.stringify(details || {}),
                            timestamp: new Date().toISOString()
                        })
                    });
                });
            } catch(e) { /* silent */ }
        }
        vbAnalytics('page_view', {page: 'best_practices'});

        (function () {
            'use strict';

            // --- Constants ---
            var API_BASE = '/api/data/v9.2/';

            var SEVERITY_LABELS = {
                10001000: 'Critical',
                10001001: 'Warning',
                10001002: 'Info'
            };

            var SEVERITY_CLASSES = {
                10001000: 'critical',
                10001001: 'warning',
                10001002: 'info'
            };

            var SEVERITY_ORDER = {
                10001000: 0,
                10001001: 1,
                10001002: 2
            };

            var CATEGORY_LABELS = {
                10001000: 'Deprecated Feature',
                10001001: 'Unsupported Code',
                10001002: 'Naming Convention',
                10001003: 'Error Handling',
                10001004: 'Performance',
                10001005: 'Security',
                10001006: 'Maintainability',
                10001007: 'Configuration'
            };

            var ENTERPRISE_TIER = 10001002;

            // --- DOM References ---
            var tierGate = document.getElementById('tierGate');
            var mainContent = document.getElementById('mainContent');
            var errorBanner = document.getElementById('errorBanner');
            var analysisSolutionPicker = document.getElementById('analysisSolutionPicker');
            var btnRunAnalysis = document.getElementById('btnRunAnalysis');
            var filterSolution = document.getElementById('filterSolution');
            var filterSeverity = document.getElementById('filterSeverity');
            var filterCategory = document.getElementById('filterCategory');
            var toggleResolved = document.getElementById('toggleResolved');
            var btnResetFilters = document.getElementById('btnResetFilters');
            var resultCount = document.getElementById('resultCount');
            var issuesContainer = document.getElementById('issuesContainer');
            var loadingState = document.getElementById('loadingState');
            var analysisOverlay = document.getElementById('analysisOverlay');
            var toastContainer = document.getElementById('toastContainer');
            var countTotal = document.getElementById('countTotal');
            var countCritical = document.getElementById('countCritical');
            var countWarning = document.getElementById('countWarning');
            var countInfo = document.getElementById('countInfo');
            var countResolved = document.getElementById('countResolved');

            // --- State ---
            var allIssues = [];
            var solutions = [];
            var isEnterprise = false;

            // --- Utility: API helpers ---
            function apiGet(url) {
                return fetch(API_BASE + url, {
                    method: 'GET',
                    headers: {
                        'Accept': 'application/json',
                        'OData-MaxVersion': '4.0',
                        'OData-Version': '4.0',
                        'Prefer': 'odata.include-annotations="*"'
                    },
                    credentials: 'include'
                }).then(function (response) {
                    if (!response.ok) {
                        return response.text().then(function (text) {
                            throw new Error('API error (' + response.status + '): ' + text);
                        });
                    }
                    return response.json();
                });
            }

            function apiPatch(entitySet, id, body) {
                return fetch(API_BASE + entitySet + '(' + id + ')', {
                    method: 'PATCH',
                    headers: {
                        'Content-Type': 'application/json',
                        'Accept': 'application/json',
                        'OData-MaxVersion': '4.0',
                        'OData-Version': '4.0'
                    },
                    credentials: 'include',
                    body: JSON.stringify(body)
                }).then(function (response) {
                    if (!response.ok) {
                        return response.text().then(function (text) {
                            throw new Error('API error (' + response.status + '): ' + text);
                        });
                    }
                    return response;
                });
            }

            function apiPost(action, body) {
                return fetch(API_BASE + action, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'Accept': 'application/json',
                        'OData-MaxVersion': '4.0',
                        'OData-Version': '4.0'
                    },
                    credentials: 'include',
                    body: JSON.stringify(body)
                }).then(function (response) {
                    if (!response.ok) {
                        return response.text().then(function (text) {
                            throw new Error('API error (' + response.status + '): ' + text);
                        });
                    }
                    return response.json().catch(function () { return {}; });
                });
            }

            // --- Utility: Helpers ---
            function htmlEncode(str) {
                if (!str) return '';
                var div = document.createElement('div');
                div.textContent = str;
                return div.innerHTML;
            }

            function formatDate(dateStr) {
                if (!dateStr) return '--';
                try {
                    var d = new Date(dateStr);
                    return d.toLocaleDateString(undefined, {
                        year: 'numeric',
                        month: 'short',
                        day: 'numeric'
                    }) + ' ' + d.toLocaleTimeString(undefined, {
                        hour: '2-digit',
                        minute: '2-digit'
                    });
                } catch (e) {
                    return dateStr;
                }
            }

            function showError(msg) {
                errorBanner.textContent = msg;
                errorBanner.style.display = 'block';
            }

            function clearError() {
                errorBanner.style.display = 'none';
            }

            function showToast(message, type) {
                var toast = document.createElement('div');
                toast.className = 'toast' + (type ? ' ' + type : '');
                toast.textContent = message;
                toastContainer.appendChild(toast);
                setTimeout(function () {
                    toast.style.opacity = '0';
                    toast.style.transition = 'opacity 0.3s';
                    setTimeout(function () {
                        if (toast.parentNode) {
                            toast.parentNode.removeChild(toast);
                        }
                    }, 300);
                }, 4000);
            }

            function escapeOData(str) {
                return str.replace(/'/g, "''");
            }

            // --- Tier Check ---
            function checkTier() {
                return apiGet('vb_configurations?$select=vb_license_tier&$top=1')
                    .then(function (data) {
                        var records = data.value || [];
                        if (records.length === 0) {
                            return false;
                        }
                        return records[0].vb_license_tier === ENTERPRISE_TIER;
                    })
                    .catch(function (err) {
                        showError('Failed to check license tier: ' + err.message);
                        return false;
                    });
            }

            // --- Load Solutions ---
            function loadSolutions() {
                var query = "vb_crawlconfigurations?$select=vb_crawlconfigurationid,vb_name,vb_solution_display_name" +
                    "&$filter=vb_is_active eq true&$orderby=vb_name asc";

                return apiGet(query).then(function (data) {
                    solutions = data.value || [];
                    populateSolutionDropdowns();
                }).catch(function (err) {
                    showError('Failed to load solutions: ' + err.message);
                });
            }

            function populateSolutionDropdowns() {
                // Clear existing options beyond the default
                while (analysisSolutionPicker.options.length > 1) {
                    analysisSolutionPicker.remove(1);
                }
                while (filterSolution.options.length > 1) {
                    filterSolution.remove(1);
                }

                solutions.forEach(function (sol) {
                    var displayName = sol.vb_solution_display_name || sol.vb_name;

                    var opt1 = document.createElement('option');
                    opt1.value = sol.vb_crawlconfigurationid;
                    opt1.textContent = displayName;
                    analysisSolutionPicker.appendChild(opt1);

                    var opt2 = document.createElement('option');
                    opt2.value = sol.vb_crawlconfigurationid;
                    opt2.textContent = displayName;
                    filterSolution.appendChild(opt2);
                });
            }

            // --- Load Issues ---
            function loadIssues() {
                clearError();
                showLoading(true);

                var select = '$select=vb_bestpracticeissueid,vb_name,vb_rule_id,vb_severity,vb_category,' +
                    'vb_component_name,vb_component_type_name,vb_component_id,vb_entity_logical_name,' +
                    'vb_solution_name,vb_description,vb_recommendation,vb_details,vb_detected_on,' +
                    'vb_is_resolved,_vb_crawlconfiguration_value';

                var query = 'vb_bestpracticeissues?' + select + '&$count=true';

                return apiGet(query).then(function (data) {
                    allIssues = data.value || [];
                    updateSummaryCards();
                    applyFiltersAndRender();
                    showLoading(false);
                }).catch(function (err) {
                    showError('Failed to load issues: ' + err.message);
                    showLoading(false);
                    allIssues = [];
                    updateSummaryCards();
                    renderIssues([]);
                });
            }

            function showLoading(show) {
                if (show) {
                    loadingState.style.display = 'block';
                } else {
                    loadingState.style.display = 'none';
                }
            }

            // --- Summary Cards ---
            function updateSummaryCards() {
                var total = 0;
                var critical = 0;
                var warning = 0;
                var info = 0;
                var resolved = 0;

                allIssues.forEach(function (issue) {
                    total++;
                    if (issue.vb_is_resolved) {
                        resolved++;
                    }
                    switch (issue.vb_severity) {
                        case 10001000: critical++; break;
                        case 10001001: warning++; break;
                        case 10001002: info++; break;
                    }
                });

                countTotal.textContent = total;
                countCritical.textContent = critical;
                countWarning.textContent = warning;
                countInfo.textContent = info;
                countResolved.textContent = resolved;
            }

            // --- Filtering ---
            function getFilteredIssues() {
                var solutionId = filterSolution.value;
                var severity = filterSeverity.value;
                var category = filterCategory.value;
                var showResolved = toggleResolved.checked;

                return allIssues.filter(function (issue) {
                    // Solution filter
                    if (solutionId && issue._vb_crawlconfiguration_value !== solutionId) {
                        return false;
                    }

                    // Severity filter
                    if (severity && issue.vb_severity !== parseInt(severity, 10)) {
                        return false;
                    }

                    // Category filter
                    if (category && issue.vb_category !== parseInt(category, 10)) {
                        return false;
                    }

                    // Resolved filter
                    if (!showResolved && issue.vb_is_resolved) {
                        return false;
                    }

                    return true;
                });
            }

            function sortIssues(issues) {
                return issues.sort(function (a, b) {
                    // Sort by severity (Critical first)
                    var sevA = SEVERITY_ORDER[a.vb_severity] !== undefined ? SEVERITY_ORDER[a.vb_severity] : 99;
                    var sevB = SEVERITY_ORDER[b.vb_severity] !== undefined ? SEVERITY_ORDER[b.vb_severity] : 99;
                    if (sevA !== sevB) {
                        return sevA - sevB;
                    }

                    // Then by component name
                    var nameA = (a.vb_component_name || '').toLowerCase();
                    var nameB = (b.vb_component_name || '').toLowerCase();
                    return nameA.localeCompare(nameB);
                });
            }

            function applyFiltersAndRender() {
                var filtered = getFilteredIssues();
                var sorted = sortIssues(filtered);
                resultCount.textContent = sorted.length + ' issue' + (sorted.length !== 1 ? 's' : '');
                renderIssues(sorted);
            }

            // --- Render Issues ---
            function renderIssues(issues) {
                // Remove existing issue cards (keep loading state element)
                var existingCards = issuesContainer.querySelectorAll('.issue-card, .empty-state');
                existingCards.forEach(function (el) {
                    el.parentNode.removeChild(el);
                });

                if (issues.length === 0) {
                    var emptyDiv = document.createElement('div');
                    emptyDiv.className = 'empty-state';
                    emptyDiv.innerHTML =
                        '<div class="empty-state-icon">&#9989;</div>' +
                        '<h3>No issues found</h3>' +
                        '<p>Run an analysis on a solution to find best practice issues, or adjust your filters.</p>';
                    issuesContainer.appendChild(emptyDiv);
                    return;
                }

                issues.forEach(function (issue) {
                    issuesContainer.appendChild(createIssueCard(issue));
                });
            }

            function createIssueCard(issue) {
                var card = document.createElement('div');
                card.className = 'issue-card' + (issue.vb_is_resolved ? ' resolved' : '');
                card.setAttribute('data-id', issue.vb_bestpracticeissueid);

                var sevClass = SEVERITY_CLASSES[issue.vb_severity] || 'info';
                var sevLabel = SEVERITY_LABELS[issue.vb_severity] || 'Unknown';
                var catLabel = CATEGORY_LABELS[issue.vb_category] || 'Unknown';

                // Build subtitle parts
                var subtitleParts = [];
                if (issue.vb_component_name) {
                    subtitleParts.push(htmlEncode(issue.vb_component_name));
                }
                if (issue.vb_component_type_name) {
                    subtitleParts.push(htmlEncode(issue.vb_component_type_name));
                }
                if (issue.vb_entity_logical_name) {
                    subtitleParts.push('<span style="font-family:monospace;font-size:11px;">' +
                        htmlEncode(issue.vb_entity_logical_name) + '</span>');
                }

                var html = '';
                html += '<div class="issue-main">';
                html += '<div class="issue-severity severity-' + sevClass + '"></div>';
                html += '<div class="issue-body">';

                // Header: Title + Rule ID
                html += '<div class="issue-header">';
                html += '<span class="issue-title">' + htmlEncode(issue.vb_name) + '</span>';
                if (issue.vb_rule_id) {
                    html += '<span class="issue-rule">' + htmlEncode(issue.vb_rule_id) + '</span>';
                }
                html += '</div>';

                // Badges
                html += '<div class="issue-badges">';
                html += '<span class="badge badge-' + sevClass + '">' + htmlEncode(sevLabel) + '</span>';
                html += '<span class="badge badge-category">' + htmlEncode(catLabel) + '</span>';
                if (issue.vb_is_resolved) {
                    html += '<span class="badge badge-resolved">Resolved</span>';
                }
                if (issue.vb_solution_name) {
                    html += '<span class="badge badge-component">' + htmlEncode(issue.vb_solution_name) + '</span>';
                }
                html += '</div>';

                // Subtitle
                if (subtitleParts.length > 0) {
                    html += '<div class="issue-subtitle">' + subtitleParts.join(' <span class="badge-dot">&middot;</span> ') + '</div>';
                }

                // Description
                if (issue.vb_description) {
                    html += '<div class="issue-description">' + htmlEncode(issue.vb_description) + '</div>';
                }

                // Expandable sections
                var hasRecommendation = issue.vb_recommendation;
                var hasDetails = issue.vb_details;

                if (hasRecommendation || hasDetails) {
                    html += '<div class="expandable-sections">';
                    if (hasRecommendation) {
                        var recId = 'rec-' + issue.vb_bestpracticeissueid;
                        html += '<button class="expandable-toggle" data-target="' + recId + '">';
                        html += '<span class="arrow">&#9654;</span> Recommendation';
                        html += '</button>';
                    }
                    if (hasDetails) {
                        var detId = 'det-' + issue.vb_bestpracticeissueid;
                        html += '<button class="expandable-toggle" data-target="' + detId + '">';
                        html += '<span class="arrow">&#9654;</span> Details';
                        html += '</button>';
                    }
                    html += '</div>';

                    if (hasRecommendation) {
                        html += '<div class="expandable-content recommendation" id="rec-' +
                            issue.vb_bestpracticeissueid + '">' + htmlEncode(issue.vb_recommendation) + '</div>';
                    }
                    if (hasDetails) {
                        html += '<div class="expandable-content details" id="det-' +
                            issue.vb_bestpracticeissueid + '">' + htmlEncode(issue.vb_details) + '</div>';
                    }
                }

                // Detected date
                if (issue.vb_detected_on) {
                    html += '<div style="font-size:11px;color:#9ca3af;margin-top:8px;">Detected: ' +
                        formatDate(issue.vb_detected_on) + '</div>';
                }

                html += '</div>'; // .issue-body
                html += '</div>'; // .issue-main

                // Actions
                html += '<div class="issue-actions">';
                if (issue.vb_is_resolved) {
                    html += '<button class="btn btn-sm btn-reopen" data-action="reopen" data-id="' +
                        issue.vb_bestpracticeissueid + '">Reopen</button>';
                } else {
                    html += '<button class="btn btn-sm btn-resolve" data-action="resolve" data-id="' +
                        issue.vb_bestpracticeissueid + '">Mark Resolved</button>';
                }
                html += '</div>';

                card.innerHTML = html;

                // Attach expandable toggle handlers
                var toggles = card.querySelectorAll('.expandable-toggle');
                toggles.forEach(function (toggle) {
                    toggle.addEventListener('click', function (e) {
                        e.stopPropagation();
                        var targetId = toggle.getAttribute('data-target');
                        var target = document.getElementById(targetId);
                        if (target) {
                            var isOpen = target.classList.contains('open');
                            target.classList.toggle('open');
                            toggle.classList.toggle('open');
                        }
                    });
                });

                // Attach resolve/reopen handler
                var actionBtn = card.querySelector('[data-action]');
                if (actionBtn) {
                    actionBtn.addEventListener('click', function (e) {
                        e.stopPropagation();
                        var action = actionBtn.getAttribute('data-action');
                        var issueId = actionBtn.getAttribute('data-id');
                        toggleResolvedStatus(issueId, action === 'resolve', actionBtn);
                    });
                }

                return card;
            }

            // --- Toggle Resolved ---
            function toggleResolvedStatus(issueId, resolve, btn) {
                btn.disabled = true;
                var originalText = btn.textContent;
                btn.innerHTML = '<span class="spinner spinner-sm"></span>' + (resolve ? 'Resolving...' : 'Reopening...');

                apiPatch('vb_bestpracticeissues', issueId, {
                    vb_is_resolved: resolve
                }).then(function () {
                    // Update local state
                    for (var i = 0; i < allIssues.length; i++) {
                        if (allIssues[i].vb_bestpracticeissueid === issueId) {
                            allIssues[i].vb_is_resolved = resolve;
                            break;
                        }
                    }
                    updateSummaryCards();
                    applyFiltersAndRender();
                    showToast(resolve ? 'Issue marked as resolved' : 'Issue reopened', 'success');
                }).catch(function (err) {
                    btn.disabled = false;
                    btn.textContent = originalText;
                    showToast('Failed to update issue: ' + err.message, 'error');
                });
            }

            // --- Run Analysis ---
            function runAnalysis() {
                var solutionId = analysisSolutionPicker.value;
                if (!solutionId) {
                    showToast('Please select a solution to analyze.', 'error');
                    return;
                }

                btnRunAnalysis.disabled = true;
                analysisOverlay.classList.add('active');

                apiPost('vb_AnalyzeBestPractices', {
                    CrawlConfigurationId: solutionId
                }).then(function (result) {
                    analysisOverlay.classList.remove('active');
                    btnRunAnalysis.disabled = false;

                    // Refresh issues list
                    return loadIssues().then(function () {
                        // Count results for the toast
                        var newIssues = allIssues.filter(function (i) {
                            return i._vb_crawlconfiguration_value === solutionId;
                        });
                        var critCount = 0;
                        var warnCount = 0;
                        var infoCount = 0;
                        newIssues.forEach(function (i) {
                            switch (i.vb_severity) {
                                case 10001000: critCount++; break;
                                case 10001001: warnCount++; break;
                                case 10001002: infoCount++; break;
                            }
                        });
                        var summary = 'Found ' + newIssues.length + ' issue' + (newIssues.length !== 1 ? 's' : '');
                        var parts = [];
                        if (critCount > 0) parts.push(critCount + ' critical');
                        if (warnCount > 0) parts.push(warnCount + ' warning' + (warnCount !== 1 ? 's' : ''));
                        if (infoCount > 0) parts.push(infoCount + ' info');
                        if (parts.length > 0) {
                            summary += ' (' + parts.join(', ') + ')';
                        }
                        showToast(summary, 'success');

                        // Auto-select the analyzed solution in the filter
                        filterSolution.value = solutionId;
                        applyFiltersAndRender();
                    });
                }).catch(function (err) {
                    analysisOverlay.classList.remove('active');
                    btnRunAnalysis.disabled = false;
                    showToast('Analysis failed: ' + err.message, 'error');
                });
            }

            // --- Event Handlers ---
            btnRunAnalysis.addEventListener('click', runAnalysis);

            filterSolution.addEventListener('change', applyFiltersAndRender);
            filterSeverity.addEventListener('change', applyFiltersAndRender);
            filterCategory.addEventListener('change', applyFiltersAndRender);
            toggleResolved.addEventListener('change', applyFiltersAndRender);

            btnResetFilters.addEventListener('click', function () {
                filterSolution.value = '';
                filterSeverity.value = '';
                filterCategory.value = '';
                toggleResolved.checked = false;
                applyFiltersAndRender();
            });

            // --- Initialize ---
            function init() {
                checkTier().then(function (enterprise) {
                    isEnterprise = enterprise;

                    if (!isEnterprise) {
                        vbAnalytics('feature_gate_hit', {feature: 'best_practices', tier: 'free'});
                        tierGate.classList.add('active');
                        return;
                    }

                    mainContent.classList.add('active');
                    analysisSolutionPicker.disabled = false;
                    btnRunAnalysis.disabled = false;

                    return loadSolutions().then(function () {
                        return loadIssues();
                    });
                }).catch(function (err) {
                    showError('Initialization failed: ' + err.message);
                });
            }

            init();
        })();
    </script>
</body>
</html>
