/* ============================================
   DATA STORE
   ============================================ */
const APP_KEY = 'ba-{{APPLICATION_ID}}';
let data = {{FEATURE_DATA}};
const ORIGINAL_DATA = JSON.parse(JSON.stringify(data));
const EMBEDDED_ARTIFACTS = {{EMBEDDED_ARTIFACTS}};

// CRITICAL: Initialize top-level structures FIRST to prevent TypeError crashes
data.cadrage = data.cadrage || {};
data.modules = data.modules || [];
data.dependencies = data.dependencies || [];
data.handoff = data.handoff || {};
data.cadrage.stakeholders = data.cadrage.stakeholders || [];

// Initialize applications array (multi-app support)
data.applications = data.applications || [];

// Initialize optional data structures
data.wireframeComments = data.wireframeComments || {};
data.specComments = data.specComments || {};
data.customRoles = data.customRoles || [];
data.customActions = data.customActions || [];
data.cadrage.criteria = data.cadrage.criteria || [];
data.consolidation = data.consolidation || {};
data.consolidation.e2eFlows = data.consolidation.e2eFlows || [];

// Backward compat: merge old problem/current/vision into context
if (!data.cadrage.context) {
    data.cadrage.context = {
        problem: data.cadrage.problem?.description || data.cadrage.problem || '',
        trigger: data.cadrage.problem?.trigger || '',
        currentSituation: data.cadrage.current?.tools || '',
        desiredSituation: data.cadrage.vision?.changes || '',
        painPoints: data.cadrage.current?.painPoints || (data.cadrage.stakeholders || []).flatMap(s => (s.frustrations || '').split('\n').filter(Boolean)).join('\n'),
        acceptanceCriteria: data.cadrage.vision?.results || (data.cadrage.criteria || []).map(c => c.text).join('\n')
    };
}
data.cadrage.context = data.cadrage.context || { problem: '', trigger: '', currentSituation: '', desiredSituation: '', painPoints: '', acceptanceCriteria: '' };

// Initialize comments array
data.comments = data.comments || [];

// Defensive mapping: globalScope (JSON format) -> scope (HTML format)
// Handles cases where FEATURE_DATA contains raw globalScope instead of pre-mapped scope
if (!data.cadrage.scope || (!data.cadrage.scope.inscope?.length && data.cadrage.globalScope)) {
    const gs = data.cadrage.globalScope || {};
    // Backward compat: merge old MoSCoW into binary scope
    if (gs.mustHave || gs.shouldHave || gs.couldHave) {
        data.cadrage.scope = {
            inscope: [...(gs.mustHave || []), ...(gs.shouldHave || []), ...(gs.couldHave || [])].map(s => typeof s === 'string' ? { name: s, description: '' } : s),
            outofscope: (gs.outOfScope || []).map(s => typeof s === 'string' ? { name: s, description: '' } : s)
        };
    } else {
        function normScopeItem(s) {
            if (typeof s === 'string') return { name: s, description: '' };
            if (s.name) return s;
            var nm = s.feature || s.label || s.title || JSON.stringify(s);
            var parts = [];
            if (s.priority) parts.push(s.priority.toUpperCase());
            if (s.module) parts.push('Module: ' + s.module);
            return { name: nm, description: parts.join(' — ') };
        }
        data.cadrage.scope = {
            inscope: (gs.inScope || []).map(normScopeItem),
            outofscope: (gs.outOfScope || []).map(function(s) {
                if (typeof s === 'string') return { name: s, description: '' };
                if (s.name) return s;
                return { name: s.feature || s.reason || JSON.stringify(s), description: s.reason || '' };
            })
        };
    }
}
data.cadrage.scope = data.cadrage.scope || { inscope: [], outofscope: [] };

// Backward compat: old vital/important/optional/excluded → inscope/outofscope
if (data.cadrage.scope.vital && !data.cadrage.scope.inscope?.length) {
    data.cadrage.scope.inscope = [...(data.cadrage.scope.vital || []), ...(data.cadrage.scope.important || []), ...(data.cadrage.scope.optional || [])];
    data.cadrage.scope.outofscope = data.cadrage.scope.excluded || data.cadrage.scope.outofscope || [];
}

// Defensive init: moduleSpecs (may be missing if LLM didn't follow mapping)
data.moduleSpecs = data.moduleSpecs || {};
// Ensure ALL modules have a moduleSpecs entry (prevents missing schemas)
(data.modules || []).forEach(function(m) {
    if (!data.moduleSpecs[m.code]) {
        data.moduleSpecs[m.code] = { useCases: [], businessRules: [], entities: [], permissions: [], notes: '' };
    }
    // Ensure anticipatedSections array exists and normalize strings to objects
    m.anticipatedSections = (m.anticipatedSections || []).map(function(s) {
        return typeof s === 'string' ? { code: s, name: s, description: '', resources: [] } : s;
    });
    m.applicationCode = m.applicationCode || '';
    // Initialize screens array for interface specs
    if (!data.moduleSpecs[m.code].screens) {
        data.moduleSpecs[m.code].screens = [];
    }
    // Ensure sections have initialized arrays for hierarchical data
    m.anticipatedSections.forEach(function(section) {
        section.useCases = section.useCases || [];
        section.businessRules = section.businessRules || [];
        section.resources = section.resources || [];
        section.permission = section.permission || '';
        section.route = section.route || '';
    });
});

// Normalize permissions: convert any object format to "Role|Action" pipe-delimited strings
// Handles 5 formats:
// A: "Role|Action" strings (already correct)
// B: {role, permissions: ["Read:all", ...]} with role-permission pairs
// C: {role, permissions: ["Module.Entity.Read", ...]} with path-based permissions
// D: {code, label, description} permission definitions without role assignment
// E: {role: "", permissions: []} empty entries (skip)
(data.modules || []).forEach(function(m) {
    var spec = data.moduleSpecs[m.code];
    if (!spec || !spec.permissions || spec.permissions.length === 0) return;
    // Skip if already normalized (first element is a pipe-delimited string)
    if (typeof spec.permissions[0] === 'string' && spec.permissions[0].indexOf('|') !== -1) return;
    if (typeof spec.permissions[0] !== 'object') return;

    var actionMap = {
        'read': 'Consulter', 'create': 'Créer', 'update': 'Modifier',
        'delete': 'Supprimer', 'approve': 'Valider', 'validate': 'Valider',
        'export': 'Exporter', 'admin': 'Administrer', 'import': 'Importer',
        'viewsalary': 'Consulter', 'assignteam': 'Modifier', 'cancel': 'Supprimer',
        'viewbalance': 'Consulter', 'invoicetime': 'Valider'
    };
    var normalized = [];
    var first = spec.permissions[0];

    // Detect Format D: {code, label, description} — permission codes without roles
    if (first.code && !first.role && !first.permissions) {
        // Extract actions from permission codes, assign to stakeholder roles
        var roles = (data.cadrage.stakeholders || []).map(function(s) { return s.role; }).filter(Boolean);
        if (roles.length === 0) roles = ['Administrateur', 'Responsable', 'Contributeur', 'Lecteur'];
        spec.permissions.forEach(function(permDef) {
            var code = permDef.code || '';
            var raw = code.split('.').pop(); // "Module.Entity.Read" → "Read"
            var action = actionMap[raw.toLowerCase()] || raw;
            // Assign to first role (admin) by default — better than empty
            if (roles[0]) {
                var key = roles[0] + '|' + action;
                if (normalized.indexOf(key) === -1) normalized.push(key);
            }
        });
    } else {
        // Format B/C: {role, permissions: [...]}
        spec.permissions.forEach(function(entry) {
            var role = entry.role || entry.name || '';
            if (!role) return; // Skip Format E (empty role)
            var perms = entry.permissions || entry.actions || [];
            if (perms.length === 0 && entry.permissionPattern && entry.permissionPattern.endsWith('*')) {
                ['Consulter', 'Créer', 'Modifier', 'Supprimer', 'Valider', 'Exporter'].forEach(function(a) {
                    normalized.push(role + '|' + a);
                });
                return;
            }
            perms.forEach(function(perm) {
                if (typeof perm !== 'string') return;
                var raw = perm.split(':')[0]; // "Read:all" → "Read"
                if (raw.indexOf('.') !== -1) raw = raw.split('.').pop(); // "Module.Entity.Read" → "Read"
                var action = actionMap[raw.toLowerCase()] || raw;
                var key = role + '|' + action;
                if (normalized.indexOf(key) === -1) normalized.push(key);
            });
        });
    }
    spec.permissions = normalized;
});

// Detect if modules use section-level specs (hierarchical mode)
function hasHierarchicalSpecs(mod) {
    return (mod.anticipatedSections || []).some(function(s) {
        return (s.useCases && s.useCases.length > 0) || (s.businessRules && s.businessRules.length > 0);
    });
}

// Defensive: normalize stakeholder tasks (string → array)
(data.cadrage.stakeholders || []).forEach(function(s) {
    if (typeof s.tasks === 'string') {
        s.tasks = s.tasks.split(',').map(t => t.trim()).filter(Boolean);
    }
    s.tasks = s.tasks || [];
});

// Vibe coding mode: hide non-relevant sections
const isVibeCoding = data.metadata?.vibeCoding === true;
if (isVibeCoding) {
    document.querySelectorAll('[data-vibe-hide]').forEach(el => el.style.display = 'none');
}

/* ============================================
   UTILITIES
   ============================================ */
function showNotification(message) {
    const el = document.getElementById('notification');
    el.textContent = message;
    el.classList.add('visible');
    setTimeout(() => el.classList.remove('visible'), 2500);
}

function toggleForm(formId) {
    document.getElementById(formId).classList.toggle('visible');
}

function clearForm(formId) {
    document.querySelectorAll('#' + formId + ' input, #' + formId + ' textarea').forEach(el => el.value = '');
}

function getNestedValue(obj, path) {
    return path.split('.').reduce((o, k) => (o || {})[k], obj);
}

function setNestedValue(obj, path, value) {
    const keys = path.split('.');
    let current = obj;
    for (let i = 0; i < keys.length - 1; i++) {
        if (!current[keys[i]]) current[keys[i]] = {};
        current = current[keys[i]];
    }
    current[keys[keys.length - 1]] = value;
}

function updateCounts() {
    buildNavTree();
    updateDepSelects();
}

function formatFrequency(f) {
    return { daily: 'Quotidien', weekly: 'Hebdomadaire', monthly: 'Mensuel', occasional: 'Occasionnel' }[f] || f;
}

function formatAccess(a) {
    return { admin: 'Administration', manager: 'Supervision', contributor: 'Contribution', viewer: 'Consultation' }[a] || a;
}

function formatPriority(p) {
    return { inscope: 'Dans le périmètre', outofscope: 'Hors périmètre' }[p] || p;
}

function formatLevel(l) {
    return { high: 'Fort', medium: 'Moyen', low: 'Faible' }[l] || l;
}

function formatModuleType(t) {
    return { 'data-centric': 'Données', 'workflow': 'Processus', 'reporting': 'Rapports', 'integration': 'Intégration', 'full-module': 'Complet' }[t] || t;
}

function escapeHtml(s) {
    if (s == null) return '';
    var d = document.createElement('div');
    d.textContent = String(s);
    return d.innerHTML;
}

function computeProgress() {
    var totalModules = data.modules.length;
    var modulesWithUC = 0, modulesWithBR = 0, modulesWithEntities = 0, modulesWithWireframes = 0;
    var totalUCs = 0, totalBRs = 0, totalEntities = 0;

    data.modules.forEach(function(m) {
        var spec = data.moduleSpecs[m.code] || {};
        var ucs = (spec.useCases || []).length;
        var brs = (spec.businessRules || []).length;
        var ents = (spec.entities || []).length;
        var wfs = (EMBEDDED_ARTIFACTS?.wireframes?.[m.code] || []).length + (spec.screens || []).length;
        totalUCs += ucs; totalBRs += brs; totalEntities += ents;
        if (ucs > 0) modulesWithUC++;
        if (brs > 0) modulesWithBR++;
        if (ents > 0) modulesWithEntities++;
        if (wfs > 0) modulesWithWireframes++;
    });

    var checks = [];
    if (totalModules > 0) checks.push({ done: true, label: 'Modules définis (' + totalModules + ')' });
    checks.push({ done: modulesWithUC === totalModules && totalModules > 0, label: 'Cas d\'utilisation (' + modulesWithUC + '/' + totalModules + ' modules)' });
    checks.push({ done: modulesWithBR === totalModules && totalModules > 0, label: 'Règles métier (' + modulesWithBR + '/' + totalModules + ' modules)' });
    checks.push({ done: modulesWithEntities === totalModules && totalModules > 0, label: 'Données (' + modulesWithEntities + '/' + totalModules + ' modules)' });
    checks.push({ done: modulesWithWireframes === totalModules && totalModules > 0, label: 'Maquettes (' + modulesWithWireframes + '/' + totalModules + ' modules)' });
    checks.push({ done: data.cadrage.stakeholders.length > 0, label: 'Parties prenantes (' + data.cadrage.stakeholders.length + ')' });
    checks.push({ done: (data.cadrage.scope.inscope || []).length > 0, label: 'Périmètre défini' });

    var doneCount = checks.filter(function(c) { return c.done; }).length;
    var pct = checks.length > 0 ? Math.round(doneCount / checks.length * 100) : 0;
    return { checks: checks, doneCount: doneCount, total: checks.length, pct: pct, totalUCs: totalUCs, totalBRs: totalBRs, totalEntities: totalEntities };
}

/* ============================================
   INITIALIZATION
   ============================================ */
document.addEventListener('DOMContentLoaded', function() {
    loadFromLocalStorage();
    initEditableFields();
    // Re-apply vibe hiding after DOM init (in case loadFromLocalStorage changed data)
    if (isVibeCoding) {
        document.querySelectorAll('[data-vibe-hide]').forEach(el => el.style.display = 'none');
    }
    renderStakeholders();
    renderScope();
    renderCriteria();
    renderModules();
    renderDependencies();
    renderAllModuleSpecs();
    renderConsolidation();
    renderHandoff();
    renderE2EFlows();
    buildNavTree();
    updateDepSelects();
    initInlineComments();
    renderReviewPanel();
    showSection(currentSectionId);
});
