import { BadRequestException } from '@nestjs/common';

/**
 * Per-row pax cap (client rule 2026-10-15): a transport or activity row
 * can't carry more adults / children than the customer's party on the
 * query. Seniors count against adults (the query has no senior bucket);
 * infants are out of scope.
 */
export interface PartyPax {
  adults: number;
  children: number;
}

export interface TransportRowPax {
  date?: string | null;
  adults?: number | null;
  children?: number | null;
}

export interface ActivityRowPax {
  activity_id?: string | null;
  ticket_id?: string | null;
  date?: string | null;
  age_group?: string | null;
  quantity?: number | null;
}

/** Party size from a query row (adults + children_ages). */
export function partyFromQuery(q: {
  adults?: number | null;
  children_ages?: unknown[] | null;
}): PartyPax {
  return {
    adults: Number(q.adults) || 0,
    children: Array.isArray(q.children_ages) ? q.children_ages.length : 0,
  };
}

/** Human-readable violations; empty when every row fits the party. */
export function rowPaxViolations(
  party: PartyPax,
  transports: ReadonlyArray<TransportRowPax>,
  activities: ReadonlyArray<ActivityRowPax>,
): string[] {
  const out: string[] = [];
  transports.forEach((t, i) => {
    const where = `Transport row ${i + 1}${t.date ? ` (${t.date})` : ''}`;
    if (t.adults != null && t.adults > party.adults)
      out.push(`${where}: ${t.adults} adults > ${party.adults} on the query`);
    if (t.children != null && t.children > party.children)
      out.push(`${where}: ${t.children} children > ${party.children} on the query`);
  });

  // Activity rows are saved one per age group — regroup per line.
  const groups = new Map<string, { adults: number; children: number; date?: string | null }>();
  for (const a of activities) {
    const key = `${a.activity_id ?? ''}|${a.ticket_id ?? ''}|${a.date ?? ''}`;
    const g = groups.get(key) ?? { adults: 0, children: 0, date: a.date };
    const qty = Number(a.quantity) || 0;
    if (a.age_group === 'child') g.children += qty;
    else if (a.age_group === 'adult' || a.age_group === 'senior') g.adults += qty;
    groups.set(key, g);
  }
  let n = 0;
  for (const g of groups.values()) {
    n += 1;
    const where = `Activity row ${n}${g.date ? ` (${g.date})` : ''}`;
    if (g.adults > party.adults)
      out.push(`${where}: ${g.adults} adults/seniors > ${party.adults} adults on the query`);
    if (g.children > party.children)
      out.push(`${where}: ${g.children} children > ${party.children} on the query`);
  }
  return out;
}

/** Throws 400 listing every row that exceeds the party. */
export function assertRowPaxWithinParty(
  party: PartyPax,
  transports: ReadonlyArray<TransportRowPax>,
  activities: ReadonlyArray<ActivityRowPax>,
): void {
  const v = rowPaxViolations(party, transports, activities);
  if (v.length > 0) {
    throw new BadRequestException(
      `Pax per row can't exceed the customer's party — ${v.join('; ')}`,
    );
  }
}
