/**
 * DarlinkTable — présentation et tri communs à tous les tableaux Phoenix.
 *
 * Les tableaux de saisie comportant des champs modifiables sont habillés mais
 * volontairement exclus du tri. Un tableau peut aussi être exclu explicitement
 * avec data-darlink-sort="false".
 */
(function () {
    'use strict';

    const collator = new Intl.Collator('fr', {
        numeric: true,
        sensitivity: 'base'
    });

    function normalizedText(value) {
        return String(value || '').replace(/\u00a0/g, ' ').trim();
    }

    function parseFrenchNumber(value) {
        const cleaned = normalizedText(value)
            .replace(/[^0-9,.-]/g, '')
            .replace(/\s/g, '');

        if (!cleaned || !/[0-9]/.test(cleaned)) {
            return null;
        }

        let normalized = cleaned;
        if (normalized.includes(',') && normalized.includes('.')) {
            normalized = normalized.lastIndexOf(',') > normalized.lastIndexOf('.')
                ? normalized.replace(/\./g, '').replace(',', '.')
                : normalized.replace(/,/g, '');
        } else if (normalized.includes(',')) {
            normalized = normalized.replace(',', '.');
        }

        const number = Number(normalized);
        return Number.isFinite(number) ? number : null;
    }

    function parseFrenchDate(value) {
        const text = normalizedText(value);
        let match = text.match(/^(\d{1,2})[\/.-](\d{1,2})[\/.-](\d{4})(?:\s+(\d{1,2}):(\d{2}))?/);
        if (match) {
            return new Date(
                Number(match[3]), Number(match[2]) - 1, Number(match[1]),
                Number(match[4] || 0), Number(match[5] || 0)
            ).getTime();
        }

        match = text.match(/^(\d{4})-(\d{1,2})-(\d{1,2})(?:[ T](\d{1,2}):(\d{2}))?/);
        if (match) {
            return new Date(
                Number(match[1]), Number(match[2]) - 1, Number(match[3]),
                Number(match[4] || 0), Number(match[5] || 0)
            ).getTime();
        }

        return null;
    }

    function cellValue(row, columnIndex) {
        const cell = row.cells[columnIndex];
        if (!cell) return { type: 'text', value: '' };

        const explicit = cell.dataset.sortValue;
        const raw = explicit !== undefined ? explicit : cell.textContent;
        const date = parseFrenchDate(raw);
        if (date !== null) return { type: 'number', value: date };

        const number = parseFrenchNumber(raw);
        const text = normalizedText(raw);
        if (number !== null && /^[\s\u00a0+\-]?(?:\d[\d\s\u00a0.,]*)(?:\s*(?:€|DH|%))?\s*$/i.test(text)) {
            return { type: 'number', value: number };
        }

        return { type: 'text', value: text };
    }

    function isEmptyRow(row) {
        return row.cells.length === 1 && row.cells[0].hasAttribute('colspan');
    }

    function compareRows(a, b, columnIndex, direction) {
        const left = cellValue(a.row, columnIndex);
        const right = cellValue(b.row, columnIndex);
        let result;

        if (left.type === 'number' && right.type === 'number') {
            result = left.value - right.value;
        } else {
            result = collator.compare(String(left.value), String(right.value));
        }

        return (result || a.index - b.index) * direction;
    }

    function updateIndicators(table, activeHeader, direction) {
        table.querySelectorAll('thead th.darlink-sortable').forEach(function (header) {
            const indicator = header.querySelector('.sort-indicator');
            if (indicator) indicator.textContent = header === activeHeader ? (direction === 1 ? '▲' : '▼') : '↕';
            header.setAttribute('aria-sort', header === activeHeader ? (direction === 1 ? 'ascending' : 'descending') : 'none');
        });
    }

    function sortTable(table, header) {
        const tbody = table.tBodies[0];
        if (!tbody) return;

        const columnIndex = header.cellIndex;
        const previousColumn = Number(table.dataset.sortColumn);
        const previousDirection = Number(table.dataset.sortDirection) || 1;
        const direction = previousColumn === columnIndex ? previousDirection * -1 : 1;
        const rows = Array.from(tbody.rows).filter(function (row) { return !isEmptyRow(row); });

        rows.map(function (row, index) { return { row: row, index: index }; })
            .sort(function (a, b) { return compareRows(a, b, columnIndex, direction); })
            .forEach(function (entry) { tbody.appendChild(entry.row); });

        table.dataset.sortColumn = String(columnIndex);
        table.dataset.sortDirection = String(direction);
        updateIndicators(table, header, direction);
    }

    function isActionHeader(header) {
        const label = normalizedText(header.textContent).toLocaleLowerCase('fr');
        return !label || label === 'actions' || label === 'action' || header.dataset.sortable === 'false';
    }

    function isEditableTable(table) {
        const technicalId = table.id || '';
        if (/(?:lines?|receive|preview)/i.test(technicalId)) return true;

        return !!table.querySelector('tbody input:not([type="hidden"]), tbody select, tbody textarea, tbody [contenteditable="true"]');
    }

    function initializeTable(table) {
        if (table.dataset.darlinkTableReady === 'true') return;
        table.dataset.darlinkTableReady = 'true';

        if (table.dataset.darlinkSort === 'false' || isEditableTable(table)) return;

        const headers = table.querySelectorAll('thead th');
        if (!headers.length || !table.tBodies.length) return;

        headers.forEach(function (header) {
            if (isActionHeader(header)) return;

            header.classList.add('darlink-sortable');
            header.dataset.column = String(header.cellIndex);
            header.tabIndex = 0;
            header.setAttribute('role', 'button');
            header.setAttribute('aria-sort', 'none');
            header.title = 'Cliquer pour trier';

            let indicator = header.querySelector('.sort-indicator');
            if (!indicator) {
                indicator = document.createElement('span');
                indicator.className = 'sort-indicator';
                indicator.setAttribute('aria-hidden', 'true');
                header.appendChild(document.createTextNode(' '));
                header.appendChild(indicator);
            }
            indicator.textContent = '↕';
        });
    }

    function initializeAll() {
        document.querySelectorAll('table.darlink-table, table.darlink-table-modern').forEach(initializeTable);
    }

    document.addEventListener('click', function (event) {
        const header = event.target.closest('th.darlink-sortable');
        if (!header) return;
        const table = header.closest('table');
        if (!table || table.dataset.darlinkTableReady !== 'true') return;
        event.preventDefault();
        event.stopImmediatePropagation();
        sortTable(table, header);
    }, true);

    document.addEventListener('keydown', function (event) {
        if (event.key !== 'Enter' && event.key !== ' ') return;
        const header = event.target.closest('th.darlink-sortable');
        if (!header) return;
        event.preventDefault();
        sortTable(header.closest('table'), header);
    }, true);

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initializeAll);
    } else {
        initializeAll();
    }
})();
