/**
 * GroupDealDetailDataLoader - server-side data fetcher for the Group Deal Detail page.
 *
 * Loads the base deal, its group_deals extension, and group_tiers.
 */

import { eq, and, inArray, sql } from 'drizzle-orm';
import type { DrizzleClient } from '@/server/db/client';
import { deals, vendors, dealImages, groupDeals, groupTiers } from '@/server/db/schema';
import { PUBLIC_VENDOR_STATES } from '@/server/catalog/_shared/predicates.js';
import { getReviewAggregateForDeal } from '@/server/db/queries/reviews.js';
import type { GroupDealState } from '@/lib/enums/group-deal-state';
import type { FillRule } from '@/lib/enums/fill-rule';
import type { CancellationPolicy } from '@/lib/enums/cancellation-policy';

/** A single tiered pricing band. */
export interface GroupTierData {
  id: string;
  minParticipants: number;
  pricePerUnit: number;
  discountPercent: number;
}

/** All data required for the GroupDealDetail page. */
export interface GroupDealDetailData {
  // Base deal fields
  id: string;
  title: string;
  description: string;
  specialInstructions: string | null;
  originalPrice: number;
  discountedPrice: number;
  pickupAddress: string;
  windowEnd: string | null;
  dealState: string;
  vendor: {
    id: string;
    slug: string;
    displayName: string;
    businessName: string;
  };
  images: Array<{ id: string; url: string; isPrimary: boolean; sortOrder: number }>;

  // Group-specific fields
  group: {
    id: string;
    fillRule: FillRule;
    minGroupSize: number;
    maxGroupSize: number;
    perCustomerLimit: number;
    cancellationPolicy: CancellationPolicy;
    cancellationWindowHours: number | null;
    tieredPricingEnabled: boolean;
    earlyBirdEnabled: boolean;
    earlyBirdSlots: number | null;
    earlyBirdDiscountPercent: number | null;
    socialSharingEnabled: boolean;
    socialSharingReward: string | null;
    bulkPickupEnabled: boolean;
    bulkPickupDetails: string | null;
    groupState: GroupDealState;
    currentReservationCount: number;
    extendedDeadline: string | null;
  };
  tiers: GroupTierData[];
  reviewAggregate: {
    ratingAvg: string | null;
    ratingCount: number;
  };
}

/**
 * Load a group deal by deal id with vendor, images, group extension, and tiers.
 * Returns null if not found or if the deal is not of type GROUP.
 */
export async function loadGroupDeal(
  db: DrizzleClient,
  dealId: string,
): Promise<GroupDealDetailData | null> {
  const [dealRows, imageRows] = await Promise.all([
    db
      .select({
        deal: {
          id: deals.id,
          vendorId: deals.vendorId,
          dealType: deals.dealType,
          title: deals.title,
          description: deals.description,
          isVoucher: deals.isVoucher,
          dealState: deals.dealState,
          windowEnd: deals.windowEnd,
          pickupAddress: deals.pickupAddress,
          specialInstructions: deals.specialInstructions,
          minPrice: deals.minPrice,
          stockRemaining: deals.stockRemaining,
          originalPrice: sql<string>`(SELECT original_price FROM deal_skus WHERE deal_id = ${deals.id} AND option_ids_hash = 'default' LIMIT 1)`,
          discountedPrice: sql<string>`(SELECT discounted_price FROM deal_skus WHERE deal_id = ${deals.id} AND option_ids_hash = 'default' LIMIT 1)`,
        },
        vendor: {
          id: vendors.id,
          displayName: vendors.displayName,
          businessName: vendors.businessName,
        },
        group: groupDeals,
      })
      .from(deals)
      .innerJoin(vendors, eq(deals.vendorId, vendors.id))
      .innerJoin(groupDeals, eq(groupDeals.dealId, deals.id))
      .where(and(eq(deals.id, dealId), inArray(vendors.accountState, [...PUBLIC_VENDOR_STATES])))
      .limit(1),
    db
      .select({
        id: dealImages.id,
        url: dealImages.url,
        isPrimary: dealImages.isPrimary,
        sortOrder: dealImages.sortOrder,
      })
      .from(dealImages)
      .where(eq(dealImages.dealId, dealId))
      .orderBy(dealImages.sortOrder),
  ]);

  if (!dealRows[0]) return null;
  if (dealRows[0].deal.dealType !== 'GROUP') return null;

  const reviewAggregate = await getReviewAggregateForDeal(db, dealId);

  const { deal, vendor, group } = dealRows[0];

  // Fetch tiers separately so we can handle the case where there are none
  const tierRows = group.tieredPricingEnabled
    ? await db
        .select({
          id: groupTiers.id,
          minParticipants: groupTiers.minParticipants,
          pricePerUnit: groupTiers.pricePerUnit,
          discountPercent: groupTiers.discountPercent,
        })
        .from(groupTiers)
        .where(eq(groupTiers.groupDealId, group.id))
        .orderBy(groupTiers.minParticipants)
    : [];

  return {
    id: deal.id,
    title: deal.title,
    description: deal.description,
    specialInstructions: deal.specialInstructions ?? null,
    originalPrice: parseFloat(deal.originalPrice ?? deal.minPrice ?? '0'),
    discountedPrice: parseFloat(deal.discountedPrice ?? deal.minPrice ?? '0'),
    pickupAddress: deal.pickupAddress,
    windowEnd: deal.windowEnd?.toISOString() ?? null,
    dealState: deal.dealState,
    vendor: {
      id: vendor.id,
      slug: vendor.id,
      displayName: vendor.displayName,
      businessName: vendor.businessName,
    },
    images: imageRows.map((img) => ({
      id: img.id,
      url: img.url,
      isPrimary: img.isPrimary,
      sortOrder: img.sortOrder,
    })),
    group: {
      id: group.id,
      fillRule: group.fillRule as FillRule,
      minGroupSize: group.minGroupSize,
      maxGroupSize: group.maxGroupSize,
      perCustomerLimit: group.perCustomerLimit,
      cancellationPolicy: group.cancellationPolicy as CancellationPolicy,
      cancellationWindowHours: group.cancellationWindowHours ?? null,
      tieredPricingEnabled: group.tieredPricingEnabled,
      earlyBirdEnabled: group.earlyBirdEnabled,
      earlyBirdSlots: group.earlyBirdSlots ?? null,
      earlyBirdDiscountPercent: group.earlyBirdDiscountPercent ?? null,
      socialSharingEnabled: group.socialSharingEnabled,
      socialSharingReward: group.socialSharingReward ?? null,
      bulkPickupEnabled: group.bulkPickupEnabled,
      bulkPickupDetails: group.bulkPickupDetails ?? null,
      groupState: group.groupState as GroupDealDetailData['group']['groupState'],
      currentReservationCount: group.currentReservationCount,
      extendedDeadline: group.extendedDeadline?.toISOString() ?? null,
    },
    tiers: tierRows.map((tier) => ({
      id: tier.id,
      minParticipants: tier.minParticipants,
      pricePerUnit: parseFloat(String(tier.pricePerUnit)),
      discountPercent: tier.discountPercent,
    })),
    reviewAggregate,
  };
}
