import type { FraudAdapter, EarnCtx, FraudSignal, AdapterConfig } from '../types.js'
import { eq } from 'drizzle-orm'
import { referralsTable } from '../../schema.js'

export const velocityConversionAdapter: FraudAdapter<EarnCtx> = {
  key: 'velocity-conversion',
  points: ['EARN'],
  async evaluate(ctx: EarnCtx, cfg: AdapterConfig): Promise<FraudSignal | null> {
    const minMinutes = (cfg.params?.['minMinutesToConvert'] as number | undefined) ?? 5
    const maxConversionRateThreshold =
      (cfg.params?.['maxConversionRatePct'] as number | undefined) ?? 80
    const conversionWindowDays = (cfg.params?.['conversionWindowDays'] as number | undefined) ?? 7

    // Time-to-convert: referral bind → first purchase
    const [ref] = await ctx.db
      .select({ createdAt: referralsTable.createdAt })
      .from(referralsTable)
      .where(eq(referralsTable.id, ctx.referralId))
      .limit(1)

    const purchCreatedAt = await ctx.host.getPurchaseCreatedAt(ctx.purchaseId)

    if (ref?.createdAt && purchCreatedAt) {
      const diffMinutes = (purchCreatedAt.getTime() - ref.createdAt.getTime()) / 60_000
      if (diffMinutes < minMinutes) {
        return {
          adapter: 'velocity-conversion',
          action: 'flag',
          codes: ['FAST_CONVERSION'],
          detail: { diffMinutes: Math.round(diffMinutes), threshold: minMinutes },
        }
      }
    }

    // Per-link conversion-rate anomaly over a SETTLED trailing window.
    // Both clicks and conversions come from referral_link_stats_daily (single population),
    // summed over [CURRENT_DATE - conversionWindowDays, CURRENT_DATE - 1] — settled days only,
    // so the un-rolled-up current day is never read.
    const stats = await ctx.host.getLinkConversionStats(ctx.referrerUserId, conversionWindowDays)

    if (stats.clicks > 0) {
      const rate = (stats.conversions / stats.clicks) * 100
      if (rate > maxConversionRateThreshold) {
        return {
          adapter: 'velocity-conversion',
          action: 'hold',
          codes: ['HIGH_CONVERSION_RATE'],
          detail: { ratePct: Math.round(rate), threshold: maxConversionRateThreshold },
        }
      }
    }

    return null
  },
}
