import { Time } from "@clarity-types/core";
export type Target = (number | Node);
export type Token = (string | number | number[] | string[] | (string | number)[]);
export type DecodedToken = (any | any[]);

export type MetadataCallback = (data: Metadata, playback: boolean, consentStatus?: ConsentState) => void;
export interface MetadataCallbackOptions {
    callback: MetadataCallback,
    wait: boolean,
    recall: boolean,
    called: boolean,
    consentInfo: boolean
}
export type SignalCallback = (data: ClaritySignal) => void

/* Enum */
export const enum Event {
    /* Data */
    Metric = 0,
    Dimension = 1,
    Upload = 2,
    Upgrade = 3,
    Baseline = 4,
    Discover = 5,
    Mutation = 6,
    Region = 7,
    Document = 8,
    Click = 9,
    Scroll = 10,
    Resize = 11,
    MouseMove = 12,
    MouseDown = 13,
    MouseUp = 14,
    MouseWheel = 15,
    DoubleClick = 16,
    TouchStart = 17,
    TouchEnd = 18,
    TouchMove = 19,
    TouchCancel = 20,
    Selection = 21,
    Timeline = 22,
    Page = 23,
    Custom = 24,
    Ping = 25,
    Unload = 26,
    Input = 27,
    Visibility = 28,
    Navigation = 29,
    /**
     * @deprecated No longer support Network Connection
     */
    Connection = 30,
    ScriptError = 31,
    /**
     * @deprecated No longer support Image Error
     */
    ImageError = 32,
    Log = 33,
    Variable = 34,
    Limit = 35,
    Summary = 36,
    /**
     * @deprecated No longer support Box event
     */
    Box = 37,
    Clipboard = 38,
    Submit = 39,
    Extract = 40,
    Fraud = 41,
    Change = 42,
    Snapshot = 43,
    Animation = 44,
    StyleSheetAdoption = 45,
    StyleSheetUpdate = 46,
    Consent = 47,
    ContextMenu = 48,
    // 49 is reserved for internal use
    Focus = 50,
    CustomElement = 51,
    Chat = 52,

    // Apps specific events
    WebViewDiscover = 100,
    WebViewMutation = 101,
    MutationError = 102,
    FragmentVisibility = 103,
    Keystrokes = 104,
    BackGesture = 105,
    WebViewStatus = 106,
    AppInstallReferrer = 107
    // 200-300 reserved for internal use
}

export const enum Metric {
    ClientTimestamp = 0,
    Playback = 1,
    TotalBytes = 2,
    LayoutCost = 3,
    TotalCost = 4,
    InvokeCount = 5,
    ThreadBlockedTime = 6,
    LongTaskCount = 7,
    LargestPaint = 8,
    CumulativeLayoutShift = 9,
    FirstInputDelay = 10,
    RatingValue = 11,
    RatingCount = 12,
    ProductPrice = 13,
    ScreenWidth = 14,
    ScreenHeight = 15,
    ColorDepth = 16,
    ReviewCount = 17,
    BestRating = 18,
    WorstRating = 19,
    CartPrice = 20,
    CartShipping = 21,
    CartDiscount = 22,
    CartTax = 23,
    CartTotal = 24,
    EventCount = 25,
    Automation = 26,
    Mobile = 27,
    UploadTime = 28,
    SinglePage = 29,
    /**
     * @deprecated Browser API is deprecated. Reference: https://developer.mozilla.org/en-US/docs/Web/API/Performance/memory
     */
    UsedMemory = 30,
    Iframed = 31,
    MaxTouchPoints = 32,
    HardwareConcurrency = 33,
    DeviceMemory = 34,
    Electron = 35,
    /**
     * @deprecated No longer tracking
     */
    ConstructedStyles = 36,
    /**
     * @deprecated Move it to dimension as it'll report only last value
     */
    InteractionNextPaint = 37,
    HistoryClear = 38,
    AngularZone = 39,
    // 200-300 reserved for internal use
}

export const enum Dimension {
    UserAgent = 0,
    Url = 1,
    Referrer = 2,
    PageTitle = 3,
    NetworkHosts = 4,
    SchemaType = 5,
    ProductBrand = 6,
    ProductAvailability = 7,
    AuthorName = 8,
    Language = 9,
    ProductName = 10,
    ProductCategory = 11,
    ProductSku = 12,
    ProductCurrency = 13,
    ProductCondition = 14,
    TabId = 15,
    PageLanguage = 16,
    DocumentDirection = 17,
    Headline = 18,
    MetaType = 19,
    MetaTitle = 20,
    Generator = 21,
    Platform = 22,
    PlatformVersion = 23,
    Brand = 24,
    Model = 25,
    DevicePixelRatio = 26,
    ConnectionType = 27,
    Dob = 28,
    CookieVersion = 29,
    DeviceFamily = 30, // Allows iOS SDK to override the DeviceFamily value parsed from UserAgent.
    InitialScrollTop = 31,
    InitialScrollBottom = 32,
    AncestorOrigins = 33,
    Timezone = 34,
    TimezoneOffset = 35,
    Consent = 36,
    InteractionNextPaint = 37
    // 200-300 reserved for internal use
}

export const enum Check {
    None = 0,
    Payload = 1,
    Shutdown = 2,
    Retry = 3,
    Bytes = 4,
    Collection = 5,
    Server = 6,
    Page = 7
}

export const enum Code {
    RunTask = 0,
    CssRules = 1,
    MutationObserver = 2,
    PerformanceObserver = 3,
    CallStackDepth = 4,
    Selector = 5,
    Metric = 6,
    /**
     * @deprecated No longer support ContentSecurityPolicy
     */
    ContentSecurityPolicy = 7,
    Config = 8,
    FunctionExecutionTime = 9,
    LeanLimit = 10,
    BFCache = 11,
}

export const enum Severity {
    Info = 0,
    Warning = 1,
    Error = 2,
    Fatal = 3
}

export const enum Upload {
    Async = 0,
    Beacon = 1
}

export const enum BooleanFlag {
    False = 0,
    True = 1
}

export const enum GCMConsent {
    Unknown = 0,
    Granted = 1,
    Denied = 2
}

export const enum IframeStatus {
    Unknown = 0,
    TopFrame = 1,
    Iframe = 2
}

export const enum Setting {
    Expire = 365, // 1 Year
    SessionExpire = 1, // 1 Day
    CookieVersion = 2, // Increment this version every time there's a cookie schema change
    SessionTimeout = 30 * Time.Minute, // 30 minutes
    CookieInterval = 1, // 1 Day
    PingInterval = 1 * Time.Minute, // 1 Minute
    PingTimeout = 5 * Time.Minute, // 5 Minutes
    SummaryInterval = 100, // Same events within 100ms will be collapsed into single summary
    ClickText = 25, // Maximum number of characters to send as part of Click event's text field
    ClickClass = 50, // Maximum number of characters to send as part of Click event's class name
    ClickTag = 10, // Maximum number of characters to send as part of Click event's tag
    ClickId = 25, // Maximum number of characters to send as part of Click event's id
    PayloadLimit = 128, // Do not allow more than specified payloads per page
    PageLimit = 128, // Do not allow more than 128 pages in a session
    ShutdownLimit = 2 * Time.Hour, // Shutdown instrumentation after specified time
    RetryLimit = 1, // Maximum number of attempts to upload a payload before giving up
    PlaybackBytesLimit = 10 * 1024 * 1024, // 10MB
    CollectionLimit = 128, // Number of unique entries for dimensions
    ClickPrecision = 32767, // 2^15 - 1
    ClickParentTraversal = 10, // Maximum number of parent elements to traverse when computing relative click coordinates
    BoxPrecision = 100, // Up to 2 decimal points (e.g. 34.56)
    ScriptErrorLimit = 5, // Do not send the same script error more than 5 times per page
    DimensionLimit = 256, // Do not extract dimensions which are over 256 characters
    WordLength = 5, // Estimated average size of a word,
    RestartDelay = 250, // Wait for 250ms before starting to wire up again
    CallStackDepth = 20, // Maximum call stack depth before bailing out
    RatingScale = 100, // Scale rating to specified scale
    ViewportIntersectionRatio = 0.05, // Ratio of intersection area in comparison to viewport area before it's marked visible
    IntersectionRatio = 0.8, // Ratio of intersection area in comparison to element's area before it's marked visible
    MaxFirstPayloadBytes = 1 * 1024 * 1024, // 1MB: Cap the very first payload to a maximum of 1MB
    MegaByte = 1024 * 1024, // 1MB
    UploadFactor = 3, // Slow down sequence by specified factor
    MinUploadDelay = 100, // Minimum time before we are ready to flush events to the server
    MaxUploadDelay = 30 * Time.Second, // Do flush out payload once every 30s,
    ExtractLimit = 10000, // Do not extract more than 10000 characters
    ChecksumPrecision = 28, // n-bit integer to represent token hash
    UploadTimeout = 15000, // Timeout in ms for XHR requests
    LongTask = 30, // Long Task threshold in ms
    MaxBeaconPayloadBytes = 64 * 1024, // 64KB: Cap the beacon payload to a maximum of 64KB
}

export const enum Character {
    Zero = 48,
    Nine = 57,
    At = 64,
    Blank = 32,
    Tab = 9,
    NewLine = 10,
    Return = 13
}

export const enum ApplicationPlatform {
    WebApp = 0
}

export const enum Constant {
    Auto = "Auto",
    Config = "Config",
    Clarity = "clarity",
    Restart = "restart",
    Suspend = "suspend",
    Pause = "pause",
    Resume = "resume",
    Report = "report",
    Memory = "memory",
    Empty = "",
    Space = " ",
    Expires = "expires=",
    Domain = "domain=",
    Dropped = "*na*",
    Comma = ",",
    Dot = ".",
    At = "@",
    Asterix = "*",
    Semicolon = ";",
    Equals = "=",
    Path = ";path=/",
    Target = "target",
    Blank = "_blank",
    Parent = "_parent",
    Top = "_top",
    String = "string",
    Number = "number",
    Email = "email",
    CookieKey = "_clck", // Clarity Cookie Key
    SessionKey = "_clsk", // Clarity Session Key
    TabKey = "_cltk", // Clarity Tab Key
    Pipe = "|",
    End = "END",
    Upgrade = "UPGRADE",
    Action = "ACTION",
    Signal = "SIGNAL",
    Extract = "EXTRACT",
    Snapshot = "SNAPSHOT",
    Module = "MODULE",
    UserHint = "userHint",
    UserType = "userType",
    UserId = "userId",
    SessionId = "sessionId",
    PageId = "pageId",
    Mask = "•", // Placeholder character for explicitly masked content
    Digit = "▫", // Placeholder character for digits
    Letter = "▪", // Placeholder character for letters
    SessionStorage = "sessionStorage",
    Cookie = "cookie",
    Navigation = "navigation",
    Resource = "resource",
    LongTask = "longtask",
    FID = "first-input",
    CLS = "layout-shift",
    LCP = "largest-contentful-paint",
    PerformanceEventTiming = "event",
    HTTPS = "https://",
    CompressionStream = "CompressionStream",
    Accept = "Accept",
    ClarityGzip = "application/x-clarity-gzip",
    Tilde = "~",
    ArrayStart = "[",
    ConditionStart = "{",
    ConditionEnd = "}",
    Seperator = "<SEP>",
    Timeout = "Timeout",
    Bang = "!",
    SHA256 = "SHA-256",
    Electron = "Electron",
    Caret = "^",
    Granted = "granted",
    Denied = "denied",
    AdStorage = "ad_storage",
    AnalyticsStorage = "analytics_storage",
}

export const enum XMLReadyState {
    Unsent = 0,
    Opened = 1,
    Headers_Recieved = 2,
    Loading = 3,
    Done = 4
}

export const enum ConsentSource {
    Implicit = 0,
    API = 1,
    GCM = 2,
    TCF = 3,
    APIv1 = 4,
    APIv2 = 5,
    Cookie = 6,
    Default = 7,
    // 100-255 Reserved for CMP integration, both internal and external
    ClarityShopifyPixel = 100,
    ClarityShopifyApp = 101,
    UET = 102,

    //CMPs
    CmpMyAgilePrivacy = 150,
    CmpUserCentrics = 151,
    CmpCookiebot = 152,
    CmpAxeptio = 153,
    CmpCookiehub = 154,
    CmpCookieYes = 155,
    CmpWebTofee = 156,
    CmpWPConsent = 157,
    CmpSeersAI = 158,
    // Reserved to indicate an unknown consent source
    Unknown = 255,
}

/* Helper Interfaces */

export interface Payload {
    e: Token[]; /* Envelope */
    a: Token[][]; /* Events that are used for data analysis */
    p: Token[][]; /* Events that are primarily used for session playback */
}

export interface EncodedPayload {
    e: string; /* Envelope */
    a: string; /* Analytics Payload */
    p: string; /* Playback Payload */
}

export interface Metadata {
    projectId: string;
    userId: string;
    sessionId: string;
    pageNum: number;
}

export interface Session {
    session: string;
    ts: number;
    count: number;
    upgrade: BooleanFlag;
    upload: string;
}

export interface User {
    id: string;
    version: number;
    expiry: number;
    consent: BooleanFlag;
    dob: number;
}

export interface Envelope extends Metadata {
    sequence: number;
    start: number;
    duration: number;
    version: string;
    upload: Upload;
    end: BooleanFlag;
    applicationPlatform: number;
    url: string;
}

export interface Transit {
    [key: number]: {
        data: string;
        attempts: number;
    };
}

export interface BaselineState {
    time: number;
    event: number;
    data: BaselineData;
}

/* Event Data */
export interface BaselineData {
    visible: BooleanFlag;
    docWidth: number;
    docHeight: number;
    screenWidth: number;
    screenHeight: number;
    scrollX: number;
    scrollY: number;
    pointerX: number;
    pointerY: number;
    activityTime: number;
    scrollTime: number;
    pointerTime?: number;
    moveX?: number;
    moveY?: number;
    moveTime?: number;
    downX?: number;
    downY?: number;
    downTime?: number;
    upX?: number;
    upY?: number;
    upTime?: number;
    pointerPrevX?: number;
    pointerPrevY?: number;
    pointerPrevTime?: number;
    modules: number[];
}

export interface IdentityData {
    userId: string;
    userHint: string;
    sessionId?: string;
    pageId?: string;
}

export interface DimensionData {
    [key: number]: string[];
}

export interface VariableData {
    [name: string]: string[];
}

// Eventually custom event can be expanded to contain more properties
// For now, restricting to key value pair where both key & value are strings
// The way it's different from variable is that Custom Event has a notion of time
// Whereas variables have no timing element and eventually will turn into custom dimensions
export interface CustomData {
    key?: string;
    value: string;
}

export interface MetricData {
    [key: number]: number;
}

export interface PingData {
    gap: number;
}

export interface LimitData {
    check: number;
}

export interface SummaryData {
    [event: number]: [number, number][]; // Array of [start, duration] for every event type
}

export interface UpgradeData {
    key: string;
}

export interface ExtractData {
    [key: number]: { [subkey: number]: string }; // Array of { subkey: number } representing the extracted data
}

export interface UploadData {
    sequence: number;
    attempts: number;
    status: number;
}

export interface ClaritySignal {
    type: string
    value?: number
}

export interface PerformanceEventTiming extends PerformanceEntry {
    duration: DOMHighResTimeStamp;
    interactionId: number;
}

export interface Interaction {
    id: number;
    latency: number;
}

export interface ConsentState {
    source?: ConsentSource;
    ad_Storage?: string;
    analytics_Storage?: string;
}

export const enum ConsentType {
    None = 0,
    Implicit = 1,
    General = 2
}

export interface ConsentData {
    source: ConsentSource;
    ad_Storage: BooleanFlag;
    analytics_Storage: BooleanFlag;
}

export interface GCMConsentState {
    ad_Storage: GCMConsent;
    analytics_Storage: GCMConsent;
}
