// lib/id3v2/FrameHeader.ts
import * as Token from 'token-types';
import * as util from '../common/Util.js';
import { UINT32SYNCSAFE } from './ID3v2Token.js';
import { textDecode } from '@borewit/text-codec';
import { Id3v2ContentError } from './FrameParser.js';
/**
 * Frame header length (bytes) depending on ID3v2 major version.
 */
export function getFrameHeaderLength(majorVer) {
    switch (majorVer) {
        case 2: return 6;
        case 3:
        case 4: return 10;
        default: throw makeUnexpectedMajorVersionError(majorVer);
    }
}
function readFrameFlags(b, majorVer) {
    // ID3v2.3 and ID3v2.4 use different bit layouts for the frame status and format flags.
    if (majorVer === 3) {
        // ID3v2.3: status `%abc00000`, format `%ijk00000` (https://id3.org/id3v2.3.0)
        return {
            status: {
                tag_alter_preservation: util.getBit(b, 0, 7),
                file_alter_preservation: util.getBit(b, 0, 6),
                read_only: util.getBit(b, 0, 5)
            },
            format: {
                compression: util.getBit(b, 1, 7),
                encryption: util.getBit(b, 1, 6),
                grouping_identity: util.getBit(b, 1, 5),
                // Unsynchronisation and data-length-indicator do not exist as per-frame flags in ID3v2.3.
                unsynchronisation: false,
                data_length_indicator: false
            }
        };
    }
    // ID3v2.4: status `%0abc0000`, format `%0h00kmnp` (https://id3.org/id3v2.4.0-structure)
    return {
        status: {
            tag_alter_preservation: util.getBit(b, 0, 6),
            file_alter_preservation: util.getBit(b, 0, 5),
            read_only: util.getBit(b, 0, 4)
        },
        format: {
            grouping_identity: util.getBit(b, 1, 6),
            compression: util.getBit(b, 1, 3),
            encryption: util.getBit(b, 1, 2),
            unsynchronisation: util.getBit(b, 1, 1),
            data_length_indicator: util.getBit(b, 1, 0)
        }
    };
}
/**
 * Factory: parse a frame header from its header bytes (6 for v2.2, 10 for v2.3/v2.4).
 *
 * Note: It only *parses* and does light validation. It does not read payload bytes.
 */
export function readFrameHeader(uint8Array, majorVer, warningCollector) {
    switch (majorVer) {
        case 2:
            return parseFrameHeaderV22(uint8Array, majorVer, warningCollector);
        case 3:
        case 4:
            return parseFrameHeaderV23V24(uint8Array, majorVer, warningCollector);
        default:
            throw makeUnexpectedMajorVersionError(majorVer);
    }
}
function parseFrameHeaderV22(uint8Array, majorVer, warningCollector) {
    const header = {
        id: textDecode(uint8Array.subarray(0, 3), 'ascii'),
        length: Token.UINT24_BE.get(uint8Array, 3)
    };
    if (!header.id.match(/^[A-Z0-9]{3}$/)) {
        warningCollector.addWarning(`Invalid ID3v2.${majorVer} frame-header-ID: ${header.id}`);
    }
    return header;
}
function parseFrameHeaderV23V24(uint8Array, majorVer, warningCollector) {
    const header = {
        id: textDecode(uint8Array.subarray(0, 4), 'ascii'),
        length: (majorVer === 4 ? UINT32SYNCSAFE : Token.UINT32_BE).get(uint8Array, 4),
        flags: readFrameFlags(uint8Array.subarray(8, 10), majorVer)
    };
    if (!header.id.match(/^[A-Z0-9]{4}$/)) {
        warningCollector.addWarning(`Invalid ID3v2.${majorVer} frame-header-ID: ${header.id}`);
    }
    return header;
}
function makeUnexpectedMajorVersionError(majorVer) {
    throw new Id3v2ContentError(`Unexpected majorVer: ${majorVer}`);
}
