export type NamiConfiguration = {
  appPlatformID: string;
  logLevel: string;
  namiCommands?: string[];
  namiLanguageCode?: NamiLanguageCodes;
  initialConfig?: string;
};

export type NamiLanguageCodes =
  | 'af'
  | 'ar'
  | 'ar-dz'
  | 'ast'
  | 'az'
  | 'bg'
  | 'be'
  | 'bn'
  | 'br'
  | 'bs'
  | 'ca'
  | 'cs'
  | 'cy'
  | 'da'
  | 'de'
  | 'dsb'
  | 'el'
  | 'en'
  | 'en-au'
  | 'en-gb'
  | 'eo'
  | 'es'
  | 'es-ar'
  | 'es-co'
  | 'es-mx'
  | 'es-ni'
  | 'es-ve'
  | 'et'
  | 'eu'
  | 'fa'
  | 'fi'
  | 'fr'
  | 'fy'
  | 'ga'
  | 'gd'
  | 'gl'
  | 'he'
  | 'hi'
  | 'hr'
  | 'hsb'
  | 'hu'
  | 'hy'
  | 'ia'
  | 'id'
  | 'ig'
  | 'io'
  | 'is'
  | 'it'
  | 'ja'
  | 'ka'
  | 'kab'
  | 'kk'
  | 'km'
  | 'kn'
  | 'ko'
  | 'ky'
  | 'lb'
  | 'lt'
  | 'lv'
  | 'mk'
  | 'ml'
  | 'mn'
  | 'mr'
  | 'my'
  | 'nb'
  | 'ne'
  | 'nl'
  | 'nn'
  | 'os'
  | 'pa'
  | 'pl'
  | 'pt'
  | 'pt-br'
  | 'ro'
  | 'ru'
  | 'sk'
  | 'sl'
  | 'sq'
  | 'sr'
  | 'sr-latn'
  | 'sv'
  | 'sw'
  | 'ta'
  | 'te'
  | 'tg'
  | 'th'
  | 'tk'
  | 'tr'
  | 'tt'
  | 'udm'
  | 'uk'
  | 'ur'
  | 'uz'
  | 'vi'
  | 'zh-hans'
  | 'zh-hant';

export type NamiSKU = {
  id: string;
  name?: string;
  skuId: string;
  appleProduct?: AppleProduct;
  googleProduct?: GoogleProduct;
  amazonProduct?: AmazonProduct;
  type: NamiSKUType;
  promoId?: string | null;
  promoToken?: string | null;
  promoOffer?: { [key: string]: string } | null;
};

export enum NamiPurchaseState {
  PENDING = 'pending',
  PURCHASED = 'purchased',
  CONSUMED = 'consumed',
  RESUBSCRIBED = 'resubscribed',
  UNSUBSCRIBED = 'unsubscribed',
  DEFERRED = 'deferred',
  FAILED = 'failed',
  CANCELLED = 'cancelled',
  UNKNOWN = 'unknown',
}

export enum NamiRestorePurchasesState {
  STARTED = 'started',
  FINISHED = 'finished',
  ERROR = 'error',
}

export type NamiSKUType = 'unknown' | 'one_time_purchase' | 'subscription';

export type AppleProduct = {
  localizedDescription: string;
  localizedMultipliedPrice: string;
  localizedPrice: string;
  localizedTitle: string;
  price: string;
  priceCurrency: string;
  priceLanguage: string;
};

export type GoogleProduct = Record<string, never>;

export type AmazonProduct = Record<string, never>;

// NamiCampaignManager
export type NamiCampaign = {
  name: string;
  rule: string;
  segment: string;
  paywall: string;
  type: NamiCampaignRuleType;
  value?: string | null;
  form_factors: NamiFormFactor[];
  external_segment: string | null;
};

export enum NamiCampaignRuleType {
  DEFAULT = 'default',
  LABEL = 'label',
  UNKNOWN = 'unknown',
  URL = 'url',
}

type NamiFormFactor = {
  form_factor?: string;
  supports_portrait?: boolean;
  supports_landscape?: boolean;
};

export enum LaunchCampaignError {
  DEFAULT_CAMPAIGN_NOT_FOUND = 0,
  LABELED_CAMPAIGN_NOT_FOUND = 1,
  CAMPAIGN_DATA_NOT_FOUND = 2,
  PAYWALL_ALREADY_DISPLAYED = 3,
  SDK_NOT_INITIALIZED = 4,
  PAYWALL_COULD_NOT_DISPLAY = 5,
  URL_CAMPAIGN_NOT_FOUND = 6,
  PRODUCT_DATA_NOT_FOUND = 7,
  PRODUCT_GROUPS_NOT_FOUND = 8,
}

export type NamiError = {
  domain: string;
  code: number;
  message: string;
};

export enum LaunchCampaignResultAction {
  FAILURE = 'FAILURE',
  SUCCESS = 'SUCCESS',
}

export type FailureResultObject = {
  error: string;
};

/**
 * Permitted value types for entries in {@link PaywallLaunchContext.customAttributes}.
 *
 * Values are matched strictly by type: the string "true" and the boolean true are
 * distinct values that never compare equal. A key present with any non-null value —
 * including false or "false" — is considered "set". Passing `null` (or omitting the
 * key) means the attribute is not set; the native bridge omits null values entirely.
 */
export type CustomAttributeValue = string | boolean | number | null;

export type PaywallLaunchContext = {
  // Can contain multiple product group identifiers
  productGroups?: string[];
  // Key-value pairs used to override template values
  customAttributes: {
    [key: string]: CustomAttributeValue;
  };
  // Custom object used as data source for advanced paywall components
  customObject?: {
    [key: string]: unknown;
  };
};

export type CustomerJourneyState = {
  formerSubscriber: boolean;
  inGracePeriod: boolean;
  inTrialPeriod: boolean;
  inIntroOfferPeriod: boolean;
  isCancelled: boolean;
  inPause: boolean;
  inAccountHold: boolean;
};

export type AccountStateAction =
  | 'login'
  | 'logout'
  | 'advertising_id_set'
  | 'vendor_id_set'
  | 'customer_data_platform_id_set'
  | 'nami_device_id_set'
  | 'advertising_id_cleared'
  | 'vendor_id_cleared'
  | 'customer_data_platform_id_cleared'
  | 'nami_device_id_cleared'
  | 'anonymous_mode_on'
  | 'anonymous_mode_off';

// NamiEntitlementManager
export type NamiEntitlement = {
  activePurchases: NamiPurchase[];
  desc: string;
  name: string;
  purchasedSkus: NamiSKU[];
  referenceId: string;
  relatedSkus: NamiSKU[];
};

/**
 * Host-managed purchase payload handed back to the SDK on a successful
 * `buysku` handoff (`complete({ kind: 'purchase', result: 'success', details })`).
 * Fields are a superset across stores; the native bridge maps them onto the
 * platform's own `NamiPurchaseSuccess` (Apple flat class / Android sealed
 * GooglePlay|Amazon) at the boundary. Renamed from `NamiPurchaseDetails` for
 * cross-SDK naming consistency (NAM-1560 §2.3).
 */
export type NamiPurchaseSuccess = {
  product: NamiSKU;
  transactionID?: string;
  originalTransactionID?: string;
  orderId?: string;
  purchaseToken?: string;
  receiptId?: string;
  localizedPrice?: string;
  price?: string;
  currencyCode?: string;
  userId?: string;
  marketplace?: string;
  storeType?: string; // 'Apple', 'GooglePlay', 'Amazon'
};

/**
 * @deprecated Renamed to {@link NamiPurchaseSuccess} for cross-SDK naming
 * consistency. Structurally identical; kept so existing host code keeps
 * compiling. Prefer `NamiPurchaseSuccess` in new code.
 */
export type NamiPurchaseDetails = NamiPurchaseSuccess;

export type NamiPurchaseSuccessApple = {
  product: NamiSKU;
  transactionID: string;
  originalTransactionID: string;
  price: string;
  currencyCode: string;
};

export type NamiPurchaseSuccessGooglePlay = {
  product: NamiSKU;
  orderId: string;
  purchaseToken: string;
};

export type NamiPurchaseSuccessAmazon = {
  product: NamiSKU;
  receiptId: string;
  localizedPrice: string;
  userId: string;
  marketplace: string;
};

export enum NamiPaywallAction {
  BUY_SKU = 'BUY_SKU',
  SELECT_SKU = 'SELECT_SKU',
  RESTORE_PURCHASES = 'RESTORE_PURCHASES',
  SIGN_IN = 'SIGN_IN',
  CLOSE_PAYWALL = 'CLOSE_PAYWALL',
  SHOW_PAYWALL = 'SHOW_PAYWALL',
  PURCHASE_SELECTED_SKU = 'PURCHASE_SELECTED_SKU',
  PURCHASE_SUCCESS = 'PURCHASE_SUCCESS',
  PURCHASE_FAILED = 'PURCHASE_FAILED',
  PURCHASE_CANCELLED = 'PURCHASE_CANCELLED',
  PURCHASE_PENDING = 'PURCHASE_PENDING',
  PURCHASE_UNKNOWN = 'PURCHASE_UNKNOWN',
  PURCHASE_DEFERRED = 'PURCHASE_DEFERRED',
  DEEPLINK = 'DEEPLINK',
  TOGGLE_CHANGE = 'TOGGLE_CHANGE',
  PAGE_CHANGE = 'PAGE_CHANGE',
  SLIDE_CHANGE = 'SLIDE_CHANGE',
  COLLAPSIBLE_DRAWER_OPEN = 'COLLAPSIBLE_DRAWER_OPEN',
  COLLAPSIBLE_DRAWER_CLOSE = 'COLLAPSIBLE_DRAWER_CLOSE',
  VIDEO_STARTED = 'VIDEO_STARTED',
  VIDEO_PAUSED = 'VIDEO_PAUSED',
  VIDEO_RESUMED = 'VIDEO_RESUMED',
  VIDEO_ENDED = 'VIDEO_ENDED',
  VIDEO_CHANGED = 'VIDEO_CHANGED',
  VIDEO_MUTED = 'VIDEO_MUTED',
  VIDEO_UNMUTED = 'VIDEO_UNMUTED',
  UNKNOWN = 'UNKNOWN',
}

// NamiPurchaseManager
export type NamiPurchase = {
  sku?: NamiSKU;
  skuId: string;
  transactionIdentifier?: string;
  originalTransactionIdentifier?: string;
  purchaseToken?: string;
  expires?: Date;
  purchaseInitiatedTimestamp: Date;
  purchaseSource?: 'CAMPAIGN' | 'MARKETPLACE' | 'UNKNOWN';
};

export type NamiPurchaseFromBridge = {
  sku?: NamiSKU;
  skuId: string;
  transactionIdentifier?: string;
  originalTransactionIdentifier?: string;
  purchaseToken?: string;
  expires?: number;
  purchaseInitiatedTimestamp: number;
  purchaseSource?: 'CAMPAIGN' | 'MARKETPLACE' | 'UNKNOWN';
};

export type NamiPurchasesState =
  | 'pending'
  | 'purchased'
  | 'consumed'
  | 'resubscribed'
  | 'unsubscribed'
  | 'deferred'
  | 'failed'
  | 'cancelled'
  | 'unknown';

export type NamiPaywallEvent = {
  action: NamiPaywallAction;
  campaignId?: string;
  campaignName?: string;
  campaignType?: string;
  campaignLabel?: string;
  campaignUrl?: string;
  paywallId?: string;
  paywallName?: string;
  componentChange?: NamiPaywallComponentChange;
  segmentId?: string;
  externalSegmentId?: string;
  deeplinkUrl?: string;
  sku?: NamiSKU;
  purchaseError?: string;
  purchases?: NamiPurchase[];
  videoMetadata?: NamiPaywallEventVideoMetadata;
  timeSpentOnPaywall?: number;
};

export type NamiPaywallActionHandler = (event: NamiPaywallEvent) => void;

export type NamiPaywallComponentChange = {
  id?: string;
  name?: string;
};

export type NamiPaywallEventVideoMetadata = {
  id?: string;
  name?: string;
  url?: string;
  loopVideo: boolean;
  muteByDefault: boolean;
  autoplayVideo: boolean;
  contentTimecode?: number;
  contentDuration?: number;
};

/**
 * Native → JS handoff delivery payload. `handoffId` correlates the eventual
 * `complete(outcome)` back to the native pending handoff (NAM-1560 §2.8).
 */
export type NamiFlowHandoffPayload = {
  handoffId: string;
  handoffTag: string;
  handoffData?: Record<string, unknown>;
};

// ---------------------------------------------------------------------------
// Variant D — structured handoff outcomes (NAM-1560). Mirrors the core TS
// reference (sdk/core, NAM-1557 / PR #392). Keep the shapes in sync; the native
// bridges decode these dicts into the platform `NamiHandoffOutcome`.
// ---------------------------------------------------------------------------

/** Open-ended host-asserted attribute values — primitives only (no nesting). */
export type NamiHandoffAttributeValue = string | number | boolean;

/**
 * Host-asserted login result. Only `loginId` is required. `attributes` is
 * open-ended experience data (e.g. `{ subscriberStatus, subscribedTier }`) read
 * by branch conditions and smart text via `login.<hostKey>`; never merged into
 * Nami subscriber state and never touches entitlements.
 */
export type NamiLoginSuccess = {
  loginId: string;
  cdpId?: string;
  attributes?: Record<string, NamiHandoffAttributeValue>;
};

/** Permission types reportable from a handoff. Tier-1 (push/location/tracking)
 *  carry completion wire values natively; the rest are state/lifecycle only. */
export const NamiPermissionOutcome = {
  Push: 'push',
  Location: 'location',
  Tracking: 'tracking',
  Camera: 'camera',
  Microphone: 'microphone',
  Photos: 'photos',
  Contacts: 'contacts',
  Bluetooth: 'bluetooth',
  Calendar: 'calendar',
  Biometrics: 'biometrics',
  Health: 'health',
  Motion: 'motion',
  Speech: 'speech',
  LocalNetwork: 'localNetwork',
} as const;
export type NamiPermissionOutcome =
  (typeof NamiPermissionOutcome)[keyof typeof NamiPermissionOutcome];

/** Typed outcome reported by the host's `complete(...)`. Discriminated on `kind`
 *  (purchase/login further discriminated on `result`). */
export type NamiHandoffOutcome =
  | { kind: 'done' }
  | {
      kind: 'permission';
      permission: NamiPermissionOutcome;
      granted: boolean;
      detail?: string;
    }
  | { kind: 'purchase'; result: 'success'; details: NamiPurchaseSuccess }
  | { kind: 'purchase'; result: 'cancelled' }
  | { kind: 'purchase'; result: 'failed'; error?: unknown }
  | { kind: 'login'; result: 'success'; details: NamiLoginSuccess }
  | { kind: 'login'; result: 'cancelled' }
  | { kind: 'login'; result: 'failed'; error?: unknown };

/** Per-handoff completion callback. Bare `complete()` ≙ `complete({kind:'done'})`. */
export type NamiHandoffComplete = (outcome?: NamiHandoffOutcome) => void;

/** The single handoff handler shape (NAM-1560 §2.1 — no dual registration). */
export type NamiFlowHandoffStepHandler = (
  handoffTag: string,
  handoffData: Record<string, unknown> | undefined,
  complete: NamiHandoffComplete,
) => void;

/** Closed-but-extensible handoff tag vocabulary (mirrors the builder's
 *  `FlowHandoffTag`, minus `__*__` internals). Unknown future tags still pass. */
export const NamiHandoffTag = {
  Push: 'push',
  Location: 'location',
  Tracking: 'att',
  Deeplink: 'deeplink',
  Complete: 'complete',
  SignIn: 'signin',
  Restore: 'restore',
  SignInMvpd: 'signin_mvpd',
  BuySku: 'buysku',
  UserData: 'userdata',
} as const;
export type NamiKnownHandoffTag =
  (typeof NamiHandoffTag)[keyof typeof NamiHandoffTag];
// eslint-disable-next-line @typescript-eslint/ban-types
export type NamiHandoffTagValue = NamiKnownHandoffTag | (string & {});

/** Outbound `userdata` envelope (Nami → customer) delivered with the `userdata` tag. */
export type NamiUserDataEnvelope = {
  form_id: string;
  step_id: string;
  /** ISO-8601 UTC timestamp of delivery. */
  collected_at: string;
  fields: Record<string, boolean | string>;
};

export type NamiAccountStateEvent = {
  action: AccountStateAction;
  success: boolean;
  error?: number;
};
