import { $convertFromMarkdownString, $convertToMarkdownString, TRANSFORMERS } from "@lexical/markdown";
import { $createTableCellNode, $createTableNode, $createTableRowNode, $isTableCellNode, $isTableNode, $isTableRowNode, TableCellHeaderStates, TableCellNode, TableNode, TableRowNode } from "@lexical/table";
import { $isParagraphNode, $isTextNode, TextNode } from "lexical";
const UNDERLINE_EXPORTER_AND_TRANSFORMER = {
    dependencies: [
        TextNode
    ],
    export: (node, _, exportFormat)=>{
        if ($isTextNode(node) && node.hasFormat('underline')) return '<u>' + exportFormat(node, node.getTextContent()) + '</u>';
        return null;
    },
    importRegExp: /<u>(.*?)<\/u>/,
    regExp: /<u>(.*?)<\/u>$/,
    replace: (textNode, match)=>{
        textNode.setFormat('underline');
        textNode.setTextContent(match[1] ?? '');
        return textNode;
    },
    trigger: '>',
    type: 'text-match'
};
const UNDERLINE_IMPORTER = {
    dependencies: [
        TextNode
    ],
    export: ()=>null,
    regExp: /<u>(.*?)<\/u>/,
    replace: (_, children, match)=>{
        for (const child of children)if ($isTextNode(child)) {
            child.setFormat('underline');
            child.setTextContent(match[1] ?? '');
        }
    },
    type: 'element'
};
const TABLE_ROW_REG_EXP = /^(?:\|)(.+)(?:\|)\s?$/;
const TABLE_ROW_DIVIDER_REG_EXP = /^\|(?:\s*:?-+:?\s*\|)+\s*$/;
const TABLE = {
    dependencies: [
        TableNode,
        TableRowNode,
        TableCellNode
    ],
    export: (node)=>{
        if (!$isTableNode(node)) return null;
        const output = [];
        for (const row of node.getChildren()){
            const rowOutput = [];
            if (!$isTableRowNode(row)) continue;
            let isHeaderRow = false;
            for (const cell of row.getChildren())if ($isTableCellNode(cell)) {
                rowOutput.push($convertToMarkdownString(RTE_TRANSFORMERS, cell).replace(/\n/g, '\\n'));
                if (cell.__headerState === TableCellHeaderStates.ROW) isHeaderRow = true;
            }
            output.push(`| ${rowOutput.join(' | ')} |`);
            if (isHeaderRow) output.push(`| ${rowOutput.map(()=>'---').join(' | ')} |`);
        }
        return output.join('\n');
    },
    regExp: TABLE_ROW_REG_EXP,
    replace: (parentNode, _1, match)=>{
        const matchText = match[0] ?? '';
        if (TABLE_ROW_DIVIDER_REG_EXP.test(matchText)) {
            const table = parentNode.getPreviousSibling();
            if (!table || !$isTableNode(table)) return;
            const rows = table.getChildren();
            const lastRow = rows[rows.length - 1];
            if (!lastRow || !$isTableRowNode(lastRow)) return;
            convertToHeaderCells(lastRow.getChildren());
            parentNode.remove();
            return;
        }
        const matchCells = mapToTableCells(matchText);
        if (null == matchCells) return;
        const rows = [
            matchCells
        ];
        let sibling = parentNode.getPreviousSibling();
        let maxCells = matchCells.length;
        let isHeaderRow = false;
        while(sibling){
            if (!$isParagraphNode(sibling)) break;
            if (1 !== sibling.getChildrenSize()) break;
            const firstChild = sibling.getFirstChild();
            if (!$isTextNode(firstChild)) break;
            if (TABLE_ROW_DIVIDER_REG_EXP.test(firstChild.getTextContent())) isHeaderRow = true;
            else {
                const cells = mapToTableCells(firstChild.getTextContent());
                if (null == cells) break;
                if (isHeaderRow) {
                    convertToHeaderCells(cells);
                    isHeaderRow = false;
                }
                maxCells = Math.max(maxCells, cells.length);
                rows.unshift(cells);
            }
            const previousSibling = sibling.getPreviousSibling();
            sibling.remove();
            sibling = previousSibling;
        }
        const table = $createTableNode();
        for (const cells of rows){
            const tableRow = $createTableRowNode();
            table.append(tableRow);
            tableRow.append(...cells);
            const lenDiff = maxCells - cells.length;
            const isInHeaderRow = cells[0]?.__headerState === TableCellHeaderStates.ROW;
            for(let i = 0; i < lenDiff; i++){
                const newCell = $createTableCell('');
                if (isInHeaderRow) newCell.toggleHeaderStyle(TableCellHeaderStates.ROW);
                tableRow.append(newCell);
            }
        }
        const previousSibling = parentNode.getPreviousSibling();
        if ($isTableNode(previousSibling) && getTableColumnsSize(previousSibling) === maxCells) {
            previousSibling.append(...table.getChildren());
            parentNode.remove();
            previousSibling.selectEnd();
        } else {
            parentNode.replace(table);
            table.selectEnd();
        }
    },
    type: 'element'
};
function getTableColumnsSize(table) {
    const row = table.getFirstChild();
    return $isTableRowNode(row) ? row.getChildrenSize() : 0;
}
const $createTableCell = (textContent)=>{
    textContent = textContent.replace(/\\r?\\n/g, '\n');
    const cell = $createTableCellNode(TableCellHeaderStates.NO_STATUS);
    $convertFromMarkdownString(textContent, RTE_TRANSFORMERS, cell);
    return cell;
};
const mapToTableCells = (textContent)=>{
    const match = textContent.match(TABLE_ROW_REG_EXP);
    if (!match?.[1]) return null;
    return match[1].split('|').map((text)=>$createTableCell(text));
};
const convertToHeaderCells = (row)=>{
    row.forEach((cell)=>{
        if (!$isTableCellNode(cell)) return;
        cell.toggleHeaderStyle(TableCellHeaderStates.ROW);
    });
};
const RTE_TRANSFORMERS = [
    ...TRANSFORMERS,
    UNDERLINE_EXPORTER_AND_TRANSFORMER,
    UNDERLINE_IMPORTER,
    TABLE
];
export { RTE_TRANSFORMERS };
