/**
 * W3 — read-only MaturityHostStore over multideal purchases/deals + referral_settings.
 * Mirrors donor queries in referrals/service.ts (purchase+deal facts) and settings.ts.
 */
import { eq, inArray } from 'drizzle-orm';
import type {
  MaturityHostStore,
  RedemptionFact,
  RedemptionFactRef,
} from '@platform-modules/affiliate';
import type { DrizzleClient } from '@/server/db/client';
import { deals, dealSkus, orderLine, referralSettings } from '@/server/db/schema';
import { lineRedeemedAtSql, lineExpiresAtSql } from '@/server/fulfillment/voucher-line-state.js';
import { orderLineIdFromModuleRef, toModuleRef } from '@/server/platform-seams/ids.js';

function mapDealTypeToKind(dealType: string): 'coupon' | 'physical' {
  return dealType === 'COUPON' ? 'coupon' : 'physical';
}

function toDate(value: Date | string): Date {
  return value instanceof Date ? value : new Date(value);
}

function toNullableDate(value: Date | string | null): Date | null {
  return value == null ? null : toDate(value);
}

function toRedemptionFact(
  ref: RedemptionFactRef,
  row: {
    createdAt: Date | string;
    redeemedAt: Date | string | null;
    expiresAt: Date | string;
    dealType: string;
  },
): RedemptionFact {
  const createdAt = toDate(row.createdAt);
  return {
    sourceType: ref.sourceType,
    sourceId: ref.sourceId,
    kind: mapDealTypeToKind(row.dealType),
    paidAt: createdAt,
    purchaseCreatedAt: createdAt,
    expiresAt: toDate(row.expiresAt),
    redeemedAt: toNullableDate(row.redeemedAt),
  };
}

export function createMaturityHostStore(db: DrizzleClient): MaturityHostStore {
  return {
    async getRedemptionFacts(refs: RedemptionFactRef[]): Promise<RedemptionFact[]> {
      if (refs.length === 0) return [];

      const purchaseRefs = refs.filter((ref) => ref.sourceType === 'purchase');
      if (purchaseRefs.length === 0) return [];

      const purchaseIds = [
        ...new Set(purchaseRefs.map((ref) => toModuleRef(orderLineIdFromModuleRef(ref.sourceId)))),
      ];

      const rows = await db
        .select({
          id: orderLine.id,
          createdAt: orderLine.createdAt,
          redeemedAt: lineRedeemedAtSql(orderLine.id),
          expiresAt: lineExpiresAtSql(orderLine.id),
          dealType: deals.dealType,
        })
        .from(orderLine)
        .innerJoin(dealSkus, eq(dealSkus.id, orderLine.variantId))
        .innerJoin(deals, eq(deals.id, dealSkus.dealId))
        .where(inArray(orderLine.id, purchaseIds));

      const rowByPurchaseId = new Map(rows.map((row) => [String(row.id), row]));

      const facts: RedemptionFact[] = [];
      for (const ref of purchaseRefs) {
        const row = rowByPurchaseId.get(toModuleRef(orderLineIdFromModuleRef(ref.sourceId)));
        if (!row || !row.expiresAt) continue;
        facts.push(toRedemptionFact(ref, row as typeof row & { expiresAt: Date }));
      }
      return facts;
    },

    async getReferralSettings(): Promise<{ holdDays: number; disputeWindowDays: number }> {
      const rows = await db
        .select({
          holdDays: referralSettings.holdDays,
          disputeWindowDays: referralSettings.disputeWindowDays,
        })
        .from(referralSettings)
        .where(eq(referralSettings.id, 1))
        .limit(1);

      if (rows.length === 0) {
        throw new Error('referral_settings row not found — run migration seed');
      }

      const row = rows[0]!;
      return {
        holdDays: row.holdDays,
        disputeWindowDays: row.disputeWindowDays ?? 120,
      };
    },
  };
}
