import type { SyntaxNode, Tree } from "@lezer/common";
import type { Format, SettingOpt1, TokenRole, TokenStatus } from "src/enums";
import { Text } from "@codemirror/state"

/** Token interface */
export type Token = {
    /** Format type */
    type: Format, // 3-bit
    /** Token status */
    status: TokenStatus, // 2-bit
    /** Start offset */
    from: number, // 16-bit
    /** End offset */
    to: number, // 16-bit
    /** Token role */
    role: TokenRole, // 3-bit
    /**
     * Pointer to a specific token, which is an index refering
     * to that pointed token in its token group. If the token was
     * inside a token sequence, it will refer to its opening delimiter.
     * Otherwise, it will point to itself.
     */
    pointer: number, // 16-bit
    size: number // 8-bit
}

/** Accumulation of `ChangeSet` generated by the `composeChange` function */
export type ChangedRange = {
    /**
     * Start offset of a changed range, measured from
     * the text both before and after the change
     */
    from: number,
    /** End offset of a changed range, measured from the doc before the change */
    initTo: number,
    /** End offset of a changed range, measured from the doc after the change */
    changedTo: number;
    length: number;
}

/** Describe the rule that has to be satisfied by the delimiter */
export type DelimSpec = {
    /** Should be single character */
    char: string,
    /** Delimiter length */
    length: number,
    /**
     * If true, then delimiter length must be the same as
     * in the predetermined rule. Otherwise, the defined length
     * act as minimum length.
     */
    exactLen: boolean,
    /** Should be `TokenRole.OPEN` or `TokenRole.CLOSE` */
    role: TokenRole
}

/**
 * Used for (re)configuring the state, especially in
 * the case of document or tree change
 */
export type StateConfig = {
    doc: Text,
    tree: Tree,
    offset: number,
    settings: PluginSettings,
    maxLine?: number
}

export type NodeSpec = {
    node: SyntaxNode,
    type: string
}

export type AlignFormat = Extract<Format, Format.ALIGN_LEFT | Format.ALIGN_RIGHT | Format.ALIGN_CENTER | Format.ALIGN_JUSTIFY>;

export type MainFormat = Extract<Format, Format.INSERTION | Format.SPOILER | Format.SUPERSCRIPT | Format.SUBSCRIPT | Format.HIGHLIGHT>;

export type TokenGroup = Token[];

export type MainFormat2 = Exclude<MainFormat, Format.HIGHLIGHT>;

export type PluginSettings = {
    insertion: SettingOpt1;
    spoiler: SettingOpt1;
    superscript: SettingOpt1;
    subscript: SettingOpt1;
    customHighlight: SettingOpt1;
    customAlign: SettingOpt1;
    editorEscape: boolean;
    colorButton: boolean;
}

export type CharPos = { from: number, to: number };