/**
 * UI E2E seed — extends seed-core with a BOOKABLE trip + payment methods + promos so the portal
 * search/booking flow and the backoffice config flow have real data to drive. Runnable standalone
 * (`ts-node test/fixtures/seed-ui.ts`) or importable (`seedUi(prisma)`) from the Playwright
 * global-setup. Reads DATABASE_URL from the environment (the UI stack points at the 5544 test DB).
 *
 * Searchability: a schedule shows in POST /search when it is SCHEDULED, not package-only, has a
 * future departure on the searched date, operational coaches with AVAILABLE seats, and a resolvable
 * fare (seat-class distance formula using the seeded route-stop distances + USD→ETB rate).
 */
import { PrismaClient } from "@prisma/client";
import { IDS, resetAndSeedCore } from "./seed-core";

export const UI_IDS = {
  train: "00000000-0000-4000-8000-000000000100",
  schedule: "00000000-0000-4000-8000-000000000101",
  coach: "00000000-0000-4000-8000-000000000102",
  // Passenger.id is set EQUAL to the IAM user id. The bookings controller overrides passengerId
  // with the JWT user id (req.user.id), and the service only resolves iamUserId→passenger when it
  // is NON-UUID — since IAM ids are UUIDs, it uses the id directly, so Passenger.id must equal it.
  passenger: "11111111-0000-4000-8000-000000000001",
  promoValid: "PROMO10",
  promoExpired: "EXPIRED50",
  // Return leg C→A on the same calendar date, for ROUND_TRIP scenarios (UA-6). The route stops are
  // symmetric in distance (A=0, C=250) so the reverse leg prices identically to the outbound.
  returnSchedule: "00000000-0000-4000-8000-000000000201",
  returnCoach: "00000000-0000-4000-8000-000000000202",
} as const;

/** Days-from-now the sample trip departs (tests search on this calendar date, Addis TZ). */
export const DEPART_IN_DAYS = 2;

export function sampleDepartAt(): Date {
  const d = new Date();
  d.setUTCDate(d.getUTCDate() + DEPART_IN_DAYS);
  d.setUTCHours(6, 0, 0, 0); // 06:00Z ~ 09:00 Addis — safely same calendar day either TZ
  return d;
}

/** The date string a test passes to POST /search for the sample trip (YYYY-MM-DD). */
export function sampleDepartDate(): string {
  return sampleDepartAt().toISOString().slice(0, 10);
}

export async function seedUi(prisma: PrismaClient): Promise<void> {
  await resetAndSeedCore(prisma);

  // Give the two seed-core seat classes the exact names the portal review flow maps by.
  await prisma.seatClass.update({
    where: { id: IDS.seatClassLocal },
    data: { name: "Economy Regular" },
  });
  await prisma.seatClass.update({
    where: { id: IDS.seatClassIntl },
    data: { name: "Economy Regular Intl" },
  });

  // Enabled payment methods — the portal pay page renders ONLY enabled PaymentMethod rows.
  await prisma.paymentMethod.createMany({
    data: [
      { type: "WALLET", displayName: "Wallet", currency: "ETB", enabled: true, isDefault: true, sortOrder: 0 },
      { type: "TELEBIRR", displayName: "telebirr", currency: "ETB", enabled: true, sortOrder: 1 },
    ],
  });

  const departAt = sampleDepartAt();
  const arriveAt = new Date(departAt.getTime() + 4 * 3600_000);

  await prisma.train.create({
    data: { id: UI_IDS.train, number: "UI-100", name: "UI Test Express" },
  });

  await prisma.trainSchedule.create({
    data: {
      id: UI_IDS.schedule,
      trainId: UI_IDS.train,
      routeId: IDS.route,
      originStationId: IDS.stationA,
      destinationStationId: IDS.stationC,
      departureAt: departAt,
      arrivalAt: arriveAt,
      durationMinutes: 240,
      status: "SCHEDULED",
      stopsCount: 3,
      isPackageOnly: false,
    },
  });

  await prisma.tripStopTime.createMany({
    data: [
      { scheduleId: UI_IDS.schedule, stationId: IDS.stationA, sequence: 1, plannedDepartureAt: departAt, status: "OPEN" },
      { scheduleId: UI_IDS.schedule, stationId: IDS.stationB, sequence: 2, plannedDepartureAt: new Date(departAt.getTime() + 2 * 3600_000), status: "OPEN" },
      { scheduleId: UI_IDS.schedule, stationId: IDS.stationC, sequence: 3, plannedArrivalAt: arriveAt, status: "OPEN" },
    ],
  });

  // Enough seats that a full suite run (many bookings share one seeded DB, seats are not released
  // between specs) never exhausts availability: 12 rows × 4 cols = 48 seats.
  const SEAT_ROWS = 12;
  await prisma.coach.create({
    data: { id: UI_IDS.coach, coachTypeId: IDS.coachType, number: "UI-C1", capacity: SEAT_ROWS * 4, sequence: 1, status: "ACTIVE" },
  });
  await prisma.coachAssignment.create({
    data: { scheduleId: UI_IDS.schedule, coachId: UI_IDS.coach, positionNumber: 1, isOperational: true },
  });
  await prisma.seat.createMany({ data: buildSeats(UI_IDS.coach, SEAT_ROWS) });

  // Logged-in passenger with a funded wallet + loyalty (used by the portal storageState + WALLET pay).
  await prisma.passenger.create({ data: { id: UI_IDS.passenger } });
  await prisma.walletAccount.create({
    data: { passengerId: UI_IDS.passenger, balanceMinor: 100_000_000 },
  });
  await prisma.loyaltyAccount.create({
    data: { passengerId: UI_IDS.passenger, pointsBalance: 500 },
  });

  // Promotions (schema field names, NOT the backoffice UI names). Unique exact codes.
  await prisma.promotion.createMany({
    data: [
      { title: "10% off", code: UI_IDS.promoValid, percentOff: 10, validUntil: new Date(Date.now() + 30 * 86400_000), active: true },
      { title: "Expired", code: UI_IDS.promoExpired, percentOff: 50, validUntil: new Date(Date.now() - 86400_000), active: true },
    ],
  });

  // One baggage allowance (for excess-baggage flows later).
  await prisma.baggageAllowance.create({
    data: { seatClassId: IDS.seatClassLocal, maxWeightKg: 20, maxPiecesCount: 2, excessFeePerKg: 50 },
  });

  // ── Return leg (C→A) for ROUND_TRIP (UA-6) ──────────────────────────────────
  // Same train, same day, departs after the outbound arrives. Distances are symmetric
  // (A=0km … C=250km) so the reverse leg prices the same as the outbound.
  const returnDepart = new Date(departAt.getTime() + 8 * 3600_000); // 8h after outbound departs
  const returnArrive = new Date(returnDepart.getTime() + 4 * 3600_000);
  await prisma.trainSchedule.create({
    data: {
      id: UI_IDS.returnSchedule,
      trainId: UI_IDS.train,
      routeId: IDS.route,
      originStationId: IDS.stationC,
      destinationStationId: IDS.stationA,
      departureAt: returnDepart,
      arrivalAt: returnArrive,
      durationMinutes: 240,
      status: "SCHEDULED",
      stopsCount: 3,
      isPackageOnly: false,
    },
  });
  await prisma.tripStopTime.createMany({
    data: [
      { scheduleId: UI_IDS.returnSchedule, stationId: IDS.stationC, sequence: 1, plannedDepartureAt: returnDepart, status: "OPEN" },
      { scheduleId: UI_IDS.returnSchedule, stationId: IDS.stationB, sequence: 2, plannedDepartureAt: new Date(returnDepart.getTime() + 2 * 3600_000), status: "OPEN" },
      { scheduleId: UI_IDS.returnSchedule, stationId: IDS.stationA, sequence: 3, plannedArrivalAt: returnArrive, status: "OPEN" },
    ],
  });
  await prisma.coach.create({
    data: { id: UI_IDS.returnCoach, coachTypeId: IDS.coachType, number: "UI-C2", capacity: 48, sequence: 1, status: "ACTIVE" },
  });
  await prisma.coachAssignment.create({
    data: { scheduleId: UI_IDS.returnSchedule, coachId: UI_IDS.returnCoach, positionNumber: 1, isOperational: true },
  });
  await prisma.seat.createMany({ data: buildSeats(UI_IDS.returnCoach, 12) });
}

/** Build `rows × 4` seats (cols A–D) for a coach. */
function buildSeats(coachId: string, rows: number) {
  const cols = ["A", "B", "C", "D"];
  const seats: Array<{ coachId: string; seatNumber: string; row: number; col: string; isWindow: boolean; isAisle: boolean }> = [];
  for (let row = 1; row <= rows; row++) {
    for (const col of cols) {
      seats.push({
        coachId,
        seatNumber: `${row}${col}`,
        row,
        col,
        isWindow: col === "A" || col === "D",
        isAisle: col === "B" || col === "C",
      });
    }
  }
  return seats;
}

// Standalone runner
if (require.main === module) {
  (async () => {
    const prisma = new PrismaClient();
    try {
      await seedUi(prisma);
      // eslint-disable-next-line no-console
      console.log(`[seed-ui] done. Sample trip ${IDS.stationA}→${IDS.stationC} on ${sampleDepartDate()} (schedule ${UI_IDS.schedule}).`);
    } finally {
      await prisma.$disconnect();
    }
  })();
}
