import { columnToIndex, formatAddress, rewriteAddressForStructuralTransform } from '@bilig/formula';
import { MAX_COLS, MAX_ROWS } from '@bilig/protocol';
const CELL_REF_RE = /^\$?([A-Z]+)\$?([1-9]\d*)$/i;
export function rewriteLegacyCommentVmlForStructuralTransform(args) {
    const legacyCommentVml = args.workbook.getSheetLegacyCommentVml(args.sheetName);
    if (!legacyCommentVml) {
        return;
    }
    const nextCommentsXml = legacyCommentVml.commentsXml
        ? rewriteCommentXmlForStructuralTransform(legacyCommentVml.commentsXml, args.transform)
        : undefined;
    const nextVmlXml = rewriteVmlXmlForStructuralTransform(legacyCommentVml.vmlXml, args.transform);
    const nextCommentSignature = legacyCommentThreadSignature(args.workbook.listCommentThreads(args.sheetName));
    if (nextCommentsXml === legacyCommentVml.commentsXml &&
        nextVmlXml === legacyCommentVml.vmlXml &&
        nextCommentSignature === legacyCommentVml.commentSignature) {
        return;
    }
    args.workbook.setSheetLegacyCommentVml(args.sheetName, {
        relationshipTarget: legacyCommentVml.relationshipTarget,
        vmlXml: nextVmlXml,
        ...(legacyCommentVml.commentsRelationshipTarget !== undefined
            ? { commentsRelationshipTarget: legacyCommentVml.commentsRelationshipTarget }
            : {}),
        ...(nextCommentsXml !== undefined ? { commentsXml: nextCommentsXml } : {}),
        commentSignature: nextCommentSignature,
    });
}
function rewriteCommentXmlForStructuralTransform(xml, transform) {
    return xml.replace(/<comment\b([^>]*?)(\/>|>[\s\S]*?<\/comment>)/gu, (source, attributes) => {
        const ref = readXmlAttribute(attributes, 'ref');
        if (!ref) {
            return source;
        }
        const nextRef = rewriteCellRefForStructuralTransform(ref, transform);
        if (!nextRef) {
            return '';
        }
        return source.replace(/\bref=(["'])([\s\S]*?)\1/u, (_attribute, quote) => `ref=${quote}${nextRef}${quote}`);
    });
}
function rewriteVmlXmlForStructuralTransform(xml, transform) {
    let nextXml = xml;
    if (transform.axis === 'row') {
        nextXml = nextXml.replace(/<x:Row>(\d+)<\/x:Row>/gu, (source, rowText) => {
            const nextRow = rewriteZeroBasedRowForStructuralTransform(Number(rowText), transform);
            return nextRow === undefined ? source : `<x:Row>${String(nextRow)}</x:Row>`;
        });
    }
    else {
        nextXml = nextXml.replace(/<x:Column>(\d+)<\/x:Column>/gu, (source, columnText) => {
            const nextColumn = rewriteZeroBasedColumnForStructuralTransform(Number(columnText), transform);
            return nextColumn === undefined ? source : `<x:Column>${String(nextColumn)}</x:Column>`;
        });
    }
    return nextXml.replace(/<x:Anchor>([\s\S]*?)<\/x:Anchor>/gu, (source, body) => {
        const values = body
            .split(',')
            .map((value) => Number(value.trim()))
            .filter((value) => Number.isInteger(value));
        if (values.length !== 8) {
            return source;
        }
        const firstAxisIndex = transform.axis === 'row' ? 2 : 0;
        const secondAxisIndex = transform.axis === 'row' ? 6 : 4;
        const first = rewriteZeroBasedIndexForStructuralTransform(values[firstAxisIndex], transform);
        const second = rewriteZeroBasedIndexForStructuralTransform(values[secondAxisIndex], transform);
        if (first === undefined || second === undefined) {
            return source;
        }
        values[firstAxisIndex] = first;
        values[secondAxisIndex] = second;
        return `<x:Anchor>${values.join(', ')}</x:Anchor>`;
    });
}
function rewriteZeroBasedIndexForStructuralTransform(index, transform) {
    return transform.axis === 'row'
        ? rewriteZeroBasedRowForStructuralTransform(index, transform)
        : rewriteZeroBasedColumnForStructuralTransform(index, transform);
}
function rewriteZeroBasedRowForStructuralTransform(row, transform) {
    const rewritten = rewriteAddressForStructuralTransform(`A${String(row + 1)}`, transform);
    if (!rewritten) {
        return undefined;
    }
    const parsed = parseCellAddress(rewritten);
    return parsed && parsed[0] < MAX_ROWS ? parsed[0] : undefined;
}
function rewriteZeroBasedColumnForStructuralTransform(column, transform) {
    const rewritten = rewriteAddressForStructuralTransform(formatAddress(0, column), transform);
    if (!rewritten) {
        return undefined;
    }
    const parsed = parseCellAddress(rewritten);
    return parsed && parsed[1] < MAX_COLS ? parsed[1] : undefined;
}
function rewriteCellRefForStructuralTransform(ref, transform) {
    const rewritten = rewriteAddressForStructuralTransform(ref, transform);
    if (!rewritten) {
        return undefined;
    }
    const parsed = parseCellAddress(rewritten);
    if (!parsed || parsed[0] >= MAX_ROWS || parsed[1] >= MAX_COLS) {
        return undefined;
    }
    return formatAddress(parsed[0], parsed[1]);
}
function parseCellAddress(address) {
    const match = CELL_REF_RE.exec(address);
    return match ? [+match[2] - 1, columnToIndex(match[1].toUpperCase())] : undefined;
}
function normalizeCommentAddress(address) {
    const parsed = parseCellAddress(address);
    return parsed ? formatAddress(parsed[0], parsed[1]) : address.trim().toUpperCase();
}
function legacyCommentThreadSignature(commentThreads) {
    const normalized = commentThreads
        .map((thread) => ({
        sheetName: thread.sheetName,
        address: normalizeCommentAddress(thread.address),
        comments: thread.comments.map((comment) => ({
            body: comment.body,
            authorDisplayName: comment.authorDisplayName ?? '',
        })),
    }))
        .toSorted((left, right) => `${left.sheetName}:${left.address}`.localeCompare(`${right.sheetName}:${right.address}`));
    return JSON.stringify(normalized);
}
function readXmlAttribute(attributes, attributeName) {
    return new RegExp(`\\b${attributeName}=("|')([\\s\\S]*?)\\1`, 'u').exec(attributes)?.[2] ?? null;
}
//# sourceMappingURL=structure-legacy-comment-vml-rewrite.js.map