import { Querier } from '@platform-modules/db';

/**
 * Axis-C host-injected store for module code that needs host-owned data.
 * Host implements against its own schema; module code never imports host pgTable stubs.
 *
 * Scope is MODULE-WIDE (spec §3A Wave-4 extension), not `/fraud`-only: attribution
 * (`isSelfReferral`, `bindReferralOnSignup`) also consumes it for host-resident lookups
 * (`users.phone_index`, `referral_settings.fraud_config`).
 */

interface UserIdentityRingFields {
    phoneIndex: string | null | undefined;
    emailCanonicalIndex: string | null | undefined;
}
/** isSelfReferral: one user's phone blind-index, keyed by userId (batched fetch). */
interface PhoneBlindIndexRow {
    userId: string;
    phoneBlindIndex: string | null;
}
interface LinkConversionStats {
    clicks: number;
    conversions: number;
}
interface FraudHostStore {
    /** email-canonical: existing account with this canonical email index. */
    findExistingUserIdByEmailCanonical(canonical: string): Promise<string | undefined>;
    /** payment-instrument: card fingerprints on file for the referrer. */
    listReferrerCardFingerprints(referrerUserId: string): Promise<Array<string | null | undefined>>;
    /** EARN ctx: primary card fingerprint for a user (host payment_methods, LIMIT 1). */
    getUserCardFingerprint(userId: string): Promise<string | null | undefined>;
    /** payment-instrument: distinct referrers whose referees share this card fingerprint. */
    countDistinctReferrersForRefereeCardFingerprint(cardFingerprint: string, excludeRefereeUserId: string): Promise<number>;
    /** velocity-conversion: purchase creation timestamp for time-to-convert check. */
    getPurchaseCreatedAt(purchaseId: string): Promise<Date | null | undefined>;
    /** identity-ring: phone + canonical email indexes for a user. */
    getUserIdentityRingFields(userId: string): Promise<UserIdentityRingFields | null>;
    /** phone-required-earn: verified phone index for a user. */
    getUserPhoneIndex(userId: string): Promise<string | null | undefined>;
    /** email-catchall-domain: signups with canonical email index matching domain within rolling window. */
    countSignupsByEmailDomainInWindow(domain: string, windowHours: number): Promise<number>;
    /** velocity-conversion: settled trailing-window click/signup rollup for referrer's links. */
    getLinkConversionStats(referrerUserId: string, windowDays: number): Promise<LinkConversionStats>;
    /**
     * isSelfReferral: phone blind-indexes for the given users (host owns `users`).
     * Batched — a single `WHERE id IN (…)`. The COMPARISON
     * (index equality) stays in the module; only the FETCH is host-coupled.
     */
    getPhoneBlindIndexes(userIds: string[]): Promise<PhoneBlindIndexRow[]>;
    /**
     * bindReferralOnSignup: the host's referral fraud config (`referral_settings.fraud_config`).
     * `referral_settings` is host-resident (not affiliate-owned schema). Returns null when the
     * settings row is absent — the module decides to fail loud (ReferralSettingsNotFoundError).
     */
    getFraudConfig(): Promise<Record<string, AdapterConfig> | null>;
}

/** Adopter DB handle — generic over the host's combined schema. */
type FraudDb = Querier<Record<string, unknown>>;
type FraudAction = 'pass' | 'flag' | 'hold' | 'block';
type DecisionPoint = 'CLICK' | 'SIGNUP' | 'EARN' | 'WITHDRAW';
type StoredDecisionPoint = 'click' | 'signup' | 'earn' | 'withdraw';
declare function toStoredDecisionPoint(point: DecisionPoint): StoredDecisionPoint;
interface FraudSignal {
    adapter: string;
    action: FraudAction;
    codes: string[];
    score?: number;
    detail?: Record<string, unknown>;
}
interface AdapterConfig {
    enabled: boolean;
    /** Downgrade the adapter's natural action to at most this level. */
    action?: FraudAction;
    params?: Record<string, unknown>;
}
interface FraudAdapter<Ctx = unknown> {
    /** Stable config key — must match fraud_config[key] and registry. */
    key: string;
    points: DecisionPoint[];
    evaluate(ctx: Ctx, cfg: AdapterConfig): Promise<FraudSignal | null>;
}
interface PipelineResult {
    action: FraudAction;
    signals: FraudSignal[];
}
interface ClickCtx {
    ipHash: string;
    userAgent: string;
    country: string;
    refererUrl: string;
    linkId: string;
    visitorId?: string;
}
interface SignupCtx {
    db: FraudDb;
    host: FraudHostStore;
    refereeUserId: string;
    refereeEmail: string;
    refereePhone?: string;
    visitorId?: string;
    ipHash?: string;
    cfBotScore?: number;
}
interface EarnCtx {
    db: FraudDb;
    host: FraudHostStore;
    referralId: string;
    referrerUserId: string;
    refereeUserId: string;
    purchaseId: string;
    platformNetAgorot: number;
    refereeEmail?: string;
    refereePhone?: string;
    refereeEmailCanonical?: string;
    referrerEmailCanonical?: string;
    visitorIdReferee?: string;
    visitorIdReferrer?: string;
    cardFingerprintReferee?: string;
    cardFingerprintReferrer?: string;
}
interface WithdrawCtx {
    db: FraudDb;
    userId: string;
    amountAgorot: number;
    affiliateId: string;
}

export { type AdapterConfig as A, type ClickCtx as C, type DecisionPoint as D, type EarnCtx as E, type FraudDb as F, type LinkConversionStats as L, type PipelineResult as P, type SignupCtx as S, type UserIdentityRingFields as U, type WithdrawCtx as W, type FraudSignal as a, type FraudAdapter as b, type FraudAction as c, type FraudHostStore as d, type PhoneBlindIndexRow as e, type StoredDecisionPoint as f, toStoredDecisionPoint as t };
