interface Window {
  abtasty?: AdBlockerType<ABTastyType.ABTastyTracker>;
  dataLayer?: AdBlockerType<{ push: (event: unknown) => void }>;
  heap?: AdBlockerType<Heap.API>;
}

declare namespace ABTastyType {
  // https://developers.abtasty.com/docs/tag/tag-window-abtasty
  // AB Tasty send types
  type HitType = 'EVENT' | 'TRANSACTION' | 'VISITOREVENT' | 'SEGMENT' | string;

  // Base parameters for all hit types
  interface BaseHitParameters {
    [key: string]: boolean | number | string | undefined;
  }

  // EVENT hit type parameters
  interface EventHitParameters extends BaseHitParameters {
    ec: string; // Event Category
    ea: string; // Event Action
    el?: string; // Event Label (optional)
    ev?: number; // Event Value (optional)
  }

  // TRANSACTION hit type parameters
  interface TransactionHitParameters extends BaseHitParameters {
    tid: string; // Transaction ID
    ta?: string; // Transaction Affiliation
    tr?: number; // Transaction Revenue
    ti?: number; // Transaction Items
  }

  // VISITOREVENT hit type parameters
  interface VisitorEventHitParameters extends BaseHitParameters {
    ea: string; // Event Action
    ec?: string; // Event Category (optional)
  }

  // SEGMENT hit type parameters
  interface SegmentHitParameters extends BaseHitParameters {
    name: string; // Segment Name
    value: string; // Segment Value
  }

  // Union type for all hit parameters based on hit type
  type HitParameters<T extends HitType> = T extends 'EVENT'
    ? EventHitParameters
    : T extends 'TRANSACTION'
    ? TransactionHitParameters
    : T extends 'VISITOREVENT'
    ? VisitorEventHitParameters
    : T extends 'SEGMENT'
    ? SegmentHitParameters
    : BaseHitParameters;

  // AB Tasty send function
  type Send = <T extends HitType>(
    hit_type: T,
    hit_parameters: HitParameters<T>,
    event?: MouseEvent
  ) => void;

  interface ABTastyTracker {
    send?: Send;
  }
}

// https://developers.heap.io/reference/client-side-apis-overview
declare namespace Heap {
  type API = {
    track?: Track;
  };

  type Track = (
    eventName: string,
    eventData?: Record<string, boolean | number | string>
  ) => void;
}

type AdBlockerType<OriginalType> =
  | OriginalType
  | {
      [Key in keyof OriginalType]: never | undefined;
    }
  | undefined;
