import type { FraudAdapter, EarnCtx, SignupCtx, FraudSignal, AdapterConfig } from '../types.js';
import { sql } from 'drizzle-orm';
import { referrals } from '@/server/db/schema.js';

export const ipClusterAdapter: FraudAdapter<EarnCtx | SignupCtx> = {
  key: 'ip-cluster',
  points: ['SIGNUP', 'EARN'],
  async evaluate(ctx: EarnCtx | SignupCtx, cfg: AdapterConfig): Promise<FraudSignal | null> {
    const windowHours = Number(cfg.params?.['windowHours'] ?? 4);
    if (!Number.isInteger(windowHours) || windowHours <= 0 || windowHours > 8760) return null;
    const threshold = (cfg.params?.['clusterSize'] as number | undefined) ?? 3;

    let ipHash: string | undefined;
    let db: EarnCtx['db'];

    if ('referralId' in ctx) {
      const earnCtx = ctx as EarnCtx;
      db = earnCtx.db;
      // Load ip_hash_referee from referral row
      const [row] = await db
        .select({ ipHashReferee: referrals.ipHashReferee })
        .from(referrals)
        .where(sql`${referrals.id} = ${earnCtx.referralId}`)
        .limit(1);
      ipHash = row?.ipHashReferee ?? undefined;
    } else {
      const signupCtx = ctx as SignupCtx;
      db = signupCtx.db;
      ipHash = signupCtx.ipHash;
    }

    if (!ipHash) return null;

    const result = (await db.execute(sql`
      SELECT COUNT(*) AS cnt
      FROM referrals
      WHERE ip_hash_referee = ${ipHash}
        AND created_at >= NOW() - (INTERVAL '1 hour' * ${windowHours})
    `)) as { rows: Array<{ cnt: string }> };
    const cnt = Number((result.rows[0] as { cnt: string })?.cnt ?? 0);

    if (cnt < threshold) return null;

    return {
      adapter: 'ip-cluster',
      action: 'flag',
      codes: ['IP_CLUSTER'],
      detail: { ipHashSuffix: ipHash.slice(-8), clusterSize: cnt, windowHours },
    };
  },
};
