import * as op from 'opentype.js';

interface FontLoadError {
    type: 'timeout' | 'network' | 'format' | 'security' | 'validation' | 'DOMException' | 'unknown';
    message: string;
    details?: string[];
    originalError?: any;
}

declare class FontErrorHandler {
    failedFonts: Map<string, FontLoadError>;
    constructor();
    addFailedFont(fontName: string, error: any): void;
    getError(fontFamily: string): FontLoadError | null;
    hasError(fontFamily: string): boolean;
    destroy(): void;
    categorizeError(error: any): FontLoadError;
}

type fontFacesOptions = {
    ascentOverride?: string;
    descentOverride?: string;
    display?: FontDisplay;
    featureSettings?: string;
    lineGapOverride?: string;
    stretch?: string;
    style?: string;
    unicodeRange?: string;
    weight?: string;
};

type FontLoaderOptions = {
    useResolvers?: boolean;
    disableWarnings?: boolean;
    useCache?: boolean;
    debugLevel?: 'info' | 'warn' | 'error' | 'debug';
};
type loadParameters = {
    unitsPerEm?: number;
    timeOut?: number;
};
type loadFromUrlProps = {
    fonts: [
        {
            url: string;
            family: string;
            options?: fontFacesOptions;
        }
    ];
    params?: loadParameters;
};
type loadFromFileProps = {
    fonts: [
        {
            file: File;
            family: string;
            options?: fontFacesOptions;
        }
    ];
    params?: loadParameters;
};
type loadFromBufferProps = {
    fonts: [
        {
            buffer: ArrayBuffer;
            family: string;
            options?: fontFacesOptions;
        }
    ];
    params?: loadParameters;
};
type FontLoaderEvents = "fontLoadError" | "fontLoadProgress" | "fontLoadComplete" | "fontLoadStart" | "fontAdded" | "fontRemoved" | "fontParsed" | "fontLoadTimeout" | "fontLoadNetworkError" | "fontLoadFormatError" | "fontLoadSecurityError" | "fontLoadValidationError" | "fontLoadDOMException" | "fontLoadUnknownError" | "fontLoadSuccess" | "fontLoadWarning" | "fontLoadInfo" | "fontLoadDebug" | "fontLoadCacheHit" | "fontLoadCacheMiss" | "fontLoadCacheAdd" | "fontLoadCacheRemove" | "fontLoadCacheClear" | "fontLoadCacheHitError" | "fontLoadCacheMissError" | "fontLoadCacheAddError" | "fontLoadCacheRemoveError" | "fontLoadCacheClearError" | "fontLoadCacheHitWarning" | "fontLoadCacheMissWarning" | "fontLoadCacheAddWarning" | "fontLoadCacheRemoveWarning" | "fontLoadCacheClearWarning" | "fontLoadCacheHitInfo" | "fontLoadCacheMissInfo" | "fontLoadCacheAddInfo" | "fontLoadCacheRemoveInfo" | "fontLoadCacheClearInfo" | "fontLoadCacheHitDebug" | "fontLoadCacheMissDebug" | "fontLoadCacheAddDebug" | "fontLoadCacheRemoveDebug" | "fontLoadCacheClearDebug" | "fontLoadCacheHitSuccess" | "fontLoadCacheMissSuccess" | "fontLoadCacheAddSuccess" | "fontLoadCacheRemoveSuccess" | "fontLoadCacheClearSuccess" | "fontLoadCacheHitComplete" | "fontLoadCacheMissComplete" | "fontLoadCacheAddComplete" | "fontLoadCacheRemoveComplete" | "fontLoadCacheClearComplete" | "fontLoadCacheHitStart" | "fontLoadCacheMissStart" | "fontLoadCacheAddStart" | "fontLoadCacheRemoveStart" | "fontLoadCacheClearStart" | "fontLoadCacheHitProgress" | "fontLoadCacheMissProgress" | "fontLoadCacheAddProgress" | "fontLoadCacheRemoveProgress" | "fontLoadCacheClearProgress" | "fontLoadCacheHitTimeout" | "fontLoadCacheMissTimeout" | "fontLoadCacheAddTimeout" | "fontLoadCacheRemoveTimeout" | "fontLoadCacheClearTimeout" | "fontLoadCacheHitNetworkError" | "fontLoadCacheMissNetworkError" | "fontLoadCacheAddNetwork";

type LogLevel = 'info' | 'warn' | 'error' | 'debug' | 'reset';

declare class BaseLoader {
    private originalBuffers;
    private logger;
    /**
    *  List of font faces that have been parsed
    * @type {Map<string, op.Font>}
    * @private
    * @memberof FontLoader
    * */
    parsedFontFaces: Map<string, op.Font>;
    errorHandler: FontErrorHandler;
    constructor(debugLevel?: LogLevel);
    load(fontFaces: FontFace[], params?: loadParameters): Promise<void>;
    unload(font: string): void;
    createFromUrl(family: string, url: string, options?: fontFacesOptions): FontFace | null;
    createFromFile(file: File, family: string, options?: fontFacesOptions): Promise<FontFace | null>;
    createFromBuffer(buffer: ArrayBuffer, family: string, options?: fontFacesOptions): FontFace | null;
    destroy(): void;
    parse(family: string): void;
    setOriginalBuffer(familyName: string, font: string | ArrayBuffer): Promise<void>;
    hasBeenParsed(family: string): boolean;
}

type ValidationRule = {
    type: 'metrics' | 'glyph' | 'font' | 'names' | 'tables';
    rule: MetricsValidationRule | GlyphValidationRule;
    message?: string;
};
interface FontValidationRule {
    check: (font: op.Font) => boolean;
    fix?: (font: op.Font) => op.Font | null;
    severity: "error" | "warning";
}
interface TablesValidationRule {
    check: (font: op.Font) => boolean;
    fix?: (font: op.Font) => op.Font | null;
    severity: "error" | "warning";
}
interface NamesValidationRule {
    check: (font: op.Font) => boolean;
    fix?: (font: op.Font) => op.Font | null;
    severity: "error" | "warning";
}
interface MetricsValidationRule {
    check: (font: op.Font) => boolean;
    fix?: (font: op.Font) => op.Font | null;
    severity: "error" | "warning";
}
interface GlyphValidationRule {
    check: (glyph: op.Glyph) => boolean;
    fix?: (glyph: op.Glyph) => op.Glyph | null;
    severity: "error" | "warning";
}

/**
 * LOADER
 * @description The FontLoader class is responsible for loading font faces from various sources
 * @class FontLoader
 * @extends BaseLoader
 * @constructor FontLoader constructor options and rules for validation of font faces
 * @param {FontLoaderOptions} options
 * @param {ValidationRule[]} rules
 *
 *
 * @version 1.0.0
 *
 * @example const loader = new fontLoader({ debugLevel: 'info' })
 * @example loader.loadFromUrl({ fonts: [{ url: 'https://fonts.com/my-file.ttf', family: 'Roboto' }] })
 * @example loader.loadFromFile({ fonts: [{ file: file, family: 'Roboto' }] })
 * @example loader.loadFromBuffer({ fonts: [{ buffer: buffer, family: 'Roboto' }] })
 */
declare class FontLoader extends BaseLoader {
    /**
     *  List of font faces to load
     * @type {FontFace[]}
     * @private
     * @memberof FontLoader
     */
    private fontFaces;
    /**
     *  List of font faces that have been loaded
     * @type {Set<string>}
     * @private
     * @memberof FontLoader
     * */
    private loadedFontFaces;
    /**
     *  Options for the font loader
     * @type {FontLoaderOptions}
     * @private
     * @memberof FontLoader
     * */
    private options;
    /**
     *  Event emitter for the font loader
     * @type {EventEmitter}
     * @private
     * @memberof FontLoader
     * */
    private eventEmitter;
    constructor(options?: FontLoaderOptions, rules?: ValidationRule[]);
    loadFromUrl(args: loadFromUrlProps): Promise<void>;
    loadFromFile(args: loadFromFileProps): Promise<void>;
    loadFromBuffer(args: loadFromBufferProps): Promise<void>;
    on(event: FontLoaderEvents, listener: (...args: any[]) => void): void;
    off(event: FontLoaderEvents, listener: (...args: any[]) => void): void;
    /**
     * Get the list of font faces
     * @returns {FontFace[]}
     */
    getFontFaces(): FontFace[];
    /**
     * Get the list of loaded font faces
     * @returns {Set<string>}
     */
    getLoadedFontFaces(): Set<string>;
    /**
     * Get the list of successfully parsed font faces
     * @returns {FontFace[]}
     */
    getParsedFontFaces(): MapIterator<string>;
    /**
     * Get the list of failed font faces
     * @returns {FontFace[]}
     */
    getFailedFontFaces(): FontFace[];
    /**
     * Get the list of font face errors for a given family
     * @param {string} family
     * @returns {FontLoadError}
     */
    getFontFaceErrors(family: string): FontLoadError | null;
    isLoaded(family: string): boolean;
    isParsed(family: string): boolean;
    isErrored(family: string): boolean;
    unloadFontFaces(): void;
    unloadFontFace(family: string): void;
    unloadFontFaceByURL(url: string): void;
    /**
     * Unload a font face by file (TODO: Implement)
     * @param file
     * @deprecated
     */
    unloadFontFaceByFile(file: File): void;
    /**
     * Unload a font face by buffer (TODO: Implement)
     * @param buffer
     * @deprecated
     */
    unloadFontFaceByBuffer(buffer: ArrayBuffer): void;
    parseFontFace(family: string): void;
    destroy(): void;
}

declare function sanitizeFamilyName(familyName: string): string | null;
declare function sanitizeUrl(url: string): string | null;
declare function sanitizePath(): void;
declare function sanitizeStyle(): void;

declare function normalizeFontFaceDescriptors(descriptors: Partial<FontFaceDescriptors>): Partial<FontFaceDescriptors>;
declare function normalizeFamilyName(): void;
declare function normalizeUrl(): void;
declare function normalizePath(): void;

export { type FontLoadError, FontLoader, type FontLoaderEvents, type FontLoaderOptions, type FontValidationRule, type GlyphValidationRule, type MetricsValidationRule, type NamesValidationRule, type TablesValidationRule, type ValidationRule, type fontFacesOptions, type loadFromBufferProps, type loadFromFileProps, type loadFromUrlProps, type loadParameters, normalizeFamilyName, normalizeFontFaceDescriptors, normalizePath, normalizeUrl, sanitizeFamilyName, sanitizePath, sanitizeStyle, sanitizeUrl };
