import { LocaleData } from '@formatjs/intl-utils';

export declare function basicFormatMatcherScore(options: DateTimeFormatOptions, format: Formats): number;

/**
 * Credit: https://github.com/andyearnshaw/Intl.js/blob/0958dc1ad8153f1056653ea22b8208f0df289a4e/src/12.datetimeformat.js#L611
 * with some modifications
 * @param options
 * @param format
 */
export declare function bestFitFormatMatcherScore(options: DateTimeFormatOptions, format: Formats): number;

export declare interface DateTimeFormat {
    resolvedOptions(): ResolvedDateTimeFormatOptions;
    formatToParts(x?: number | Date): DateTimeFormatPart[];
    format(x?: number | Date): string;
}

export declare const DateTimeFormat: DateTimeFormatConstructor;

export declare interface DateTimeFormatConstructor {
    new (locales?: string | string[], options?: DateTimeFormatOptions): DateTimeFormat;
    (locales?: string | string[], options?: DateTimeFormatOptions): DateTimeFormat;
    __addLocaleData(...data: RawDateTimeLocaleData[]): void;
    supportedLocalesOf(locales: string | string[], options?: Pick<DateTimeFormatOptions, 'localeMatcher'>): string[];
    getDefaultLocale(): string;
    __defaultLocale: string;
    __defaultTimeZone: string;
    localeData: Record<string, DateTimeFormatLocaleInternalData>;
    availableLocales: string[];
    polyfilled: boolean;
    tzData: Record<string, UnpackedZoneData[]>;
    __addTZData(d: PackedData): void;
}

declare interface DateTimeFormatLocaleInternalData {
    am: string;
    pm: string;
    weekday: {
        narrow: string[];
        long: string[];
        short: string[];
    };
    era: {
        narrow: EraData;
        long: EraData;
        short: EraData;
    };
    month: {
        narrow: string[];
        long: string[];
        short: string[];
    };
    timeZoneName: TimeZoneNameData;
    /**
     * So we can construct GMT+08:00
     */
    gmtFormat: string;
    /**
     * So we can construct GMT+08:00
     */
    hourFormat: string;
    hourCycle: string;
    formats: Record<string, Formats[]>;
    nu: string[];
    hc: string[];
    ca: string[];
}

export declare interface DateTimeFormatOptions extends Intl.DateTimeFormatOptions {
    hourCycle?: 'h11' | 'h12' | 'h23' | 'h24';
    dateStyle?: 'full' | 'long' | 'medium' | 'short';
    timeStyle?: 'full' | 'long' | 'medium' | 'short';
    fractionalSecondDigits?: number;
    calendar?: 'buddhist' | 'chinese' | 'coptic' | 'ethiopia' | 'ethiopic' | 'gregory' | 'hebrew' | 'indian' | 'islamic' | 'iso8601' | 'japanese' | 'persian' | 'roc';
    numberingSystem?: string;
}

export declare interface DateTimeFormatPart {
    type: 'literal' | 'era' | 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second' | 'weekday' | 'timeZoneName' | 'dayPeriod' | 'relatedYear' | 'yearName' | 'unknown';
    value: 'string';
}

declare interface EraData {
    BC: string;
    AD: string;
}

declare type Formats = Pick<DateTimeFormatOptions, 'weekday' | 'era' | 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second' | 'timeZoneName'> & {
    hour12?: boolean;
    pattern: string;
    pattern12: string;
    skeleton: string;
};

export declare interface IntlDateTimeFormatInternal {
    locale: string;
    dataLocale: string;
    calendar?: string;
    weekday: 'narrow' | 'short' | 'long';
    era: 'narrow' | 'short' | 'long';
    year: '2-digit' | 'numeric';
    month: '2-digit' | 'numeric' | 'narrow' | 'short' | 'long';
    day: '2-digit' | 'numeric';
    hour: '2-digit' | 'numeric';
    minute: '2-digit' | 'numeric';
    second: '2-digit' | 'numeric';
    timeZoneName: 'short' | 'long';
    hourCycle: string;
    numberingSystem: string;
    timeZone: string;
    pattern: string;
    boundFormat?: Intl.DateTimeFormat['format'];
}

declare interface PackedData {
    zones: string[];
    abbrvs: string;
    offsets: string;
}

declare type RawDateTimeLocaleData = LocaleData<RawDateTimeLocaleInternalData>;

declare type RawDateTimeLocaleInternalData = Omit<DateTimeFormatLocaleInternalData, 'formats'> & {
    formats: Record<string, string[]>;
};

export declare interface ResolvedDateTimeFormatOptions {
    locale: string;
    calendar?: string;
    weekday: 'narrow' | 'short' | 'long';
    era: 'narrow' | 'short' | 'long';
    year: '2-year' | 'numeric';
    month: '2-year' | 'numeric' | 'narrow' | 'short' | 'long';
    day: '2-year' | 'numeric';
    hour: '2-year' | 'numeric';
    minute: '2-year' | 'numeric';
    second: '2-year' | 'numeric';
    timeZoneName: 'short' | 'long';
    hourCycle: string;
    numberingSystem: string;
}

declare type TimeZoneNameData = Record<string, {
    long?: [string, string];
    short?: [string, string];
}>;

/**
 * https://tc39.es/ecma402/#sec-todatetimeoptions
 * @param options
 * @param required
 * @param defaults
 */
export declare function toDateTimeOptions(options?: DateTimeFormatOptions | null, required?: string, defaults?: string): DateTimeFormatOptions;

declare type UnpackedZoneData = [number, string, number, boolean];

export { }
