/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */

import { ImplementationError } from "#MatterError.js";

/**
 * Verhoeff algorithm to compute a checksum.
 *
 * @see {@link https://en.wikipedia.org/wiki/Verhoeff_algorithm}
 */
export class Verhoeff {
    // This is rarely used so no need to keep those constants in memory
    private readonly multiply = [
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
        [1, 2, 3, 4, 0, 6, 7, 8, 9, 5],
        [2, 3, 4, 0, 1, 7, 8, 9, 5, 6],
        [3, 4, 0, 1, 2, 8, 9, 5, 6, 7],
        [4, 0, 1, 2, 3, 9, 5, 6, 7, 8],
        [5, 9, 8, 7, 6, 0, 4, 3, 2, 1],
        [6, 5, 9, 8, 7, 1, 0, 4, 3, 2],
        [7, 6, 5, 9, 8, 2, 1, 0, 4, 3],
        [8, 7, 6, 5, 9, 3, 2, 1, 0, 4],
        [9, 8, 7, 6, 5, 4, 3, 2, 1, 0],
    ];
    private readonly inverse = [0, 4, 3, 2, 1, 5, 6, 7, 8, 9];
    private readonly permute = [
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
        [1, 5, 7, 6, 2, 8, 3, 0, 9, 4],
        [5, 8, 0, 3, 7, 9, 6, 1, 4, 2],
        [8, 9, 1, 6, 0, 4, 3, 5, 2, 7],
        [9, 4, 5, 3, 1, 2, 6, 8, 7, 0],
        [4, 2, 8, 6, 5, 7, 3, 9, 0, 1],
        [2, 7, 9, 3, 8, 0, 6, 4, 1, 5],
        [7, 0, 4, 6, 9, 1, 3, 2, 5, 8],
    ];

    computeChecksum(digits: string) {
        const { length } = digits;
        let checksum = 0;
        for (let i = 1; i <= length; i++) {
            const digit = Number.parseInt(digits[length - i]);
            if (Number.isNaN(digit)) {
                throw new ImplementationError("Invalid verhoeff checksum digit");
            }
            checksum = this.multiply[checksum][this.permute[i % 8][digit]];
        }
        return this.inverse[checksum];
    }
}
