import { LOYALTY_CONFIG, loyaltyRules } from "@/lib/loyalty";

import { DESTINATIONS, ORIGIN_AIRPORTS, VEHICLES, destinationByName } from "./catalog";
import type {
  AuditRow,
  Booking,
  CommunityPost,
  ContentRow,
  Destination,
  DocumentRow,
  Flight,
  Guest,
  Hotel,
  ImportRun,
  ItineraryRow,
  MembershipTier,
  ModerationRow,
  NotificationRow,
  Payment,
  Referral,
  RewardRule,
  RewardTxn,
  Tour,
  TourManager,
  Transaction,
  Transport,
  Trip,
  TripHotel,
  UserRow,
  WishlistRow,
} from "./types";

/** Deterministic pseudo-random so server and client render identically. */
function rng(seed: number) {
  let s = seed;
  return () => {
    s = (s * 1664525 + 1013904223) % 4294967296;
    return s / 4294967296;
  };
}

const pick = <T,>(r: () => number, arr: readonly T[]): T => arr[Math.floor(r() * arr.length)]!;
const at = <T,>(arr: readonly T[], i: number): T => arr[((i % arr.length) + arr.length) % arr.length]!;

const firstNames = [
  "Rajesh", "Amit", "Sunita", "Priya", "Vikram", "Meera", "Anil", "Kavita", "Sanjay", "Neha",
  "Rahul", "Deepa", "Arun", "Shalini", "Manoj", "Rekha", "Abdul", "Farida", "Joseph", "Anita",
];
const lastNames = [
  "Sharma", "Mehta", "Iyer", "Patel", "Reddy", "Nair", "Kulkarni", "Barik", "Fernandes", "Kapoor",
];
const cities = ["Mumbai", "Delhi", "Bengaluru", "Pune", "Ahmedabad", "Chennai", "Kolkata", "Hyderabad", "Jaipur", "Kochi"];
const states = ["Maharashtra", "Delhi", "Karnataka", "Maharashtra", "Gujarat", "Tamil Nadu", "West Bengal", "Telangana", "Rajasthan", "Kerala"];

const managerNames = ["Rahul Verma", "Amit Mehta", "Sneha Rao", "Imran Sheikh", "Rajesh Sharma", "Lata Menon"];

const pad = (n: number, len = 4) => String(n).padStart(len, "0");
const dateStr = (base: Date, offsetDays: number) => {
  const d = new Date(base.getTime() + offsetDays * 86400000);
  return d.toISOString().slice(0, 10);
};
const BASE = new Date("2026-08-26T00:00:00Z");

function fullName(r: () => number) {
  return `${pick(r, firstNames)} ${pick(r, lastNames)}`;
}

const phone = (dial: string, r: () => number) => `${dial} ${100 + Math.floor(r() * 899)} ${1000 + Math.floor(r() * 8999)}`;

// ─────────────────────────────────────────────────────────── Guests

export const guests: Guest[] = (() => {
  const r = rng(11);
  return Array.from({ length: 180 }, (_, i) => {
    const name = fullName(r);
    const ci = Math.floor(r() * cities.length);
    const membership = pick(r, ["Gold", "Platinum", "Infinity", "None"] as const);
    const expiryOffset = Math.floor(r() * 1400) - 200;
    const passportStatus =
      expiryOffset < 0 ? "Expired" : expiryOffset < 180 ? "Expiring Soon" : r() > 0.3 ? "Verified" : "Pending Verification";
    return {
      id: `KV-G-${pad(1000 + i)}`,
      name,
      mobile: `+91 ${90000 + Math.floor(r() * 9999)} ${10000 + Math.floor(r() * 89999)}`,
      email: `${name.toLowerCase().replace(/ /g, ".")}${i}@example.com`,
      city: cities[ci]!,
      state: states[ci]!,
      country: "India",
      membership,
      points: Math.floor(r() * 48000),
      upcomingTrip: "",
      activeTrip: "",
      profileCompletion: 40 + Math.floor(r() * 61),
      lastTravelDate: dateStr(BASE, -Math.floor(r() * 900)),
      status: r() > 0.06 ? "Active" : "Inactive",
      createdDate: dateStr(BASE, -Math.floor(r() * 1200)),
      gender: pick(r, ["Male", "Female"]),
      dob: dateStr(BASE, -Math.floor(18000 + r() * 8000)),
      address: `${Math.floor(r() * 90) + 10}, ${pick(r, ["Palm Grove", "Rose Villa", "Sea Breeze", "Hill Crest"])}`,
      language: pick(r, ["English", "Hindi", "Marathi", "Tamil", "Gujarati"]),
      communication: pick(r, ["WhatsApp", "Email", "SMS", "Phone"]),
      passportNumber: `${pick(r, ["M", "N", "P", "S"])}${1000000 + Math.floor(r() * 8999999)}`,
      passportExpiry: dateStr(BASE, expiryOffset),
      passportStatus: passportStatus as Guest["passportStatus"],
      nationality: "Indian",
      emergencyName: fullName(r),
      emergencyRelation: pick(r, ["Son", "Daughter", "Spouse", "Sibling"]),
      emergencyMobile: `+91 ${90000 + Math.floor(r() * 9999)} ${10000 + Math.floor(r() * 89999)}`,
      diet: pick(r, ["Vegetarian", "Jain", "Vegan", "Non-Vegetarian", "Eggetarian"]),
      allergies: pick(r, ["None", "Nuts", "Lactose", "Gluten", "Shellfish"]),
      roomPreference: pick(r, ["Twin", "Double", "Single", "Suite"]),
      bedPreference: pick(r, ["Twin beds", "King", "Queen"]),
      travelPace: pick(r, ["Relaxed", "Moderate", "Active"]),
      interests: pick(r, ["Culture, Food", "Nature, Photography", "Heritage, Walking", "Wildlife, Adventure"]),
      mobility: pick(r, ["Independent", "Uses walking stick", "Limited walking", "Wheelchair assistance"]),
      healthNotes: pick(r, ["None", "Diabetes — carries medication", "Hypertension", "Knee replacement 2023"]),
      insurance: pick(r, ["TravelSecure Gold", "GlobeCare Plus", "Not provided"]),
    } satisfies Guest;
  });
})();

const guestById = new Map(guests.map((g) => [g.id, g]));

// ─────────────────────────────────────────────────────────── Destinations

export const destinations: Destination[] = DESTINATIONS.map((d, i) => ({
  id: `KV-D-${pad(100 + i, 3)}`,
  name: d.name,
  country: d.country,
  region: d.region,
  bestTime: d.bestTime,
  travelStyle: d.travelStyle,
  featured: i % 3 === 0,
  status: "Active",
}));

// ─────────────────────────────────────────────────────────── Tours (master templates)

export const tours: Tour[] = (() => {
  const r = rng(23);
  const out: Tour[] = [];
  DESTINATIONS.forEach((d) => {
    d.tours.forEach((name) => {
      const duration = d.scope === "Domestic" ? 5 + Math.floor(r() * 4) : 7 + Math.floor(r() * 7);
      out.push({
        id: `KV-T-${pad(200 + out.length, 3)}`,
        name,
        destination: d.name,
        scope: d.scope,
        duration,
        startingPrice: (d.scope === "Domestic" ? 45000 : 145000) + Math.floor(r() * 12) * 5000,
        status: r() > 0.08 ? "Active" : "Inactive",
        featured: r() > 0.72,
        membershipEligible: true,
        rewardEligible: true,
        published: pick(r, ["Published", "Published", "Published", "Review", "Draft"] as const),
        lastUpdated: dateStr(BASE, -Math.floor(r() * 120)),
      });
    });
  });
  return out;
})();

const tourByName = new Map(tours.map((t) => [t.name, t]));

// ─────────────────────────────────────────────────────────── Trips (operational journeys)

export const trips: Trip[] = (() => {
  const r = rng(37);
  return Array.from({ length: 120 }, (_, i) => {
    const tour = at(tours, i * 7 + Math.floor(r() * 3));
    const spec = destinationByName.get(tour.destination)!;
    const origin = at(ORIGIN_AIRPORTS, i + Math.floor(r() * 4));
    const dep = Math.round(-130 + (i / 119) * 285 + (r() - 0.5) * 8);
    const days = tour.duration;
    const status: Trip["status"] =
      dep + days < 0 ? "Completed" : dep <= 0 ? "Active" : dep < 30 ? "Upcoming" : r() > 0.12 ? "Confirmed" : "Draft";
    const paxCount = 6 + Math.floor(r() * 15);
    return {
      id: `KV-2026-${pad(4500 + i)}`,
      tourId: tour.id,
      tour: tour.name,
      destination: tour.destination,
      scope: tour.scope,
      originCity: origin.city,
      originAirport: origin.code,
      group: r() > 0.55 ? `Group ${pad(i, 2)}` : `${fullName(r)} party`,
      guests: paxCount,
      departure: dateStr(BASE, dep),
      returnDate: dateStr(BASE, dep + days),
      days,
      status: r() > 0.97 ? "Cancelled" : status,
      tourManager: at(managerNames, i + Math.floor(r() * 6)),
      hotel: spec.hotels[0]!.name,
      paymentStatus: pick(r, ["Paid", "Partial", "Partial", "Pending"] as const),
      visaStatus: tour.scope === "Domestic" ? "Not Required" : pick(r, ["Approved", "Approved", "Applied", "Pending"] as const),
      documentStatus: pick(r, ["Complete", "Pending", "Pending", "Issues"] as const),
    } satisfies Trip;
  });
})();

const tripById = new Map(trips.map((t) => [t.id, t]));
const specForTrip = (t: Trip) => destinationByName.get(t.destination)!;

/** Guest roster per trip — every guest, document and payment references this. */
export const tripRoster: Record<string, string[]> = (() => {
  const map: Record<string, string[]> = {};
  trips.forEach((trip, ti) => {
    const ids: string[] = [];
    for (let k = 0; k < trip.guests; k++) {
      ids.push(at(guests, ti * 13 + k * 7 + 3).id);
    }
    map[trip.id] = [...new Set(ids)];
    trip.guests = map[trip.id]!.length;
  });
  return map;
})();

export const guestsOnTrip = (tripId: string) =>
  (tripRoster[tripId] ?? []).map((id) => guestById.get(id)!).filter(Boolean);

// Backfill each guest's upcoming / active trip from the roster so they always agree.
trips.forEach((trip) => {
  const dep = new Date(trip.departure).getTime();
  const ret = new Date(trip.returnDate).getTime();
  const now = BASE.getTime() + 86400000;
  (tripRoster[trip.id] ?? []).forEach((gid) => {
    const g = guestById.get(gid);
    if (!g) return;
    if (dep <= now && ret >= now && trip.status === "Active") g.activeTrip = trip.id;
    else if (dep > now && trip.status !== "Cancelled" && !g.upcomingTrip) g.upcomingTrip = trip.id;
  });
});

// ─────────────────────────────────────────────────────────── Hotels (master)

export const hotels: Hotel[] = (() => {
  const r = rng(61);
  const out: Hotel[] = [];
  DESTINATIONS.forEach((d) => {
    d.hotels.forEach((h) => {
      out.push({
        id: `KV-H-${pad(300 + out.length, 3)}`,
        name: h.name,
        city: h.city,
        country: d.country,
        destination: d.name,
        rating: h.rating,
        address: `${Math.floor(r() * 90) + 1} ${h.city} Central`,
        phone: phone(d.dial, r),
        email: `reservations@${h.name.toLowerCase().replace(/[^a-z]/g, "")}.com`,
        roomTypes: pick(r, ["Twin, Double, Suite", "Double, Triple", "Twin, King, Suite"]),
        facilities: pick(r, ["Wi-Fi, Spa, Lift", "Wi-Fi, Restaurant, Lift", "Wi-Fi, Pool, Lift, Accessible rooms"]),
        status: "Active",
      });
    });
  });
  return out;
})();

const hotelInCity = (destination: string, city: string) =>
  hotels.find((h) => h.destination === destination && h.city === city) ??
  hotels.find((h) => h.destination === destination)!;

// ─────────────────────────────────────────────────────────── Itineraries

/** Every operating journey carries a planned itinerary and full operational data. */
const plannedTrips = trips.filter((t) => t.status !== "Draft");

const plannedIds = new Set(plannedTrips.map((t) => t.id));

export const itinerary: ItineraryRow[] = (() => {
  const r = rng(53);
  const rows: ItineraryRow[] = [];
  plannedTrips.forEach((trip, ti) => {
    const spec = specForTrip(trip);
    const dayCount = Math.min(trip.days, 10);
    for (let d = 1; d <= dayCount; d++) {
      const city = at(spec.cities, Math.floor(((d - 1) / dayCount) * spec.cities.length));
      const hotel = hotelInCity(spec.name, city);
      rows.push({
        id: `${trip.id}-D${d}`,
        tripId: trip.id,
        day: d,
        date: dateStr(new Date(trip.departure), d - 1),
        city,
        hotel: hotel.name,
        activity: at(spec.activities, ti + d),
        startTime: at(["08:30", "09:00", "09:30", "10:00"], d),
        endTime: at(["13:00", "16:30", "17:30", "18:00"], d),
        meetingPoint: at(["Hotel lobby", "Coach bay", "Station entrance", "Reception desk"], d + ti),
        transport: at(spec.transportTypes, d),
        meal: at(["Breakfast", "Breakfast, Lunch", "Breakfast, Dinner", "All meals"], d + ti),
        tourManager: trip.tourManager,
        contact: phone(spec.dial, r),
        walkingLevel: at(["Low", "Moderate", "High"] as const, d + ti),
        dressCode: spec.region === "Europe" ? "Warm layers" : spec.region === "Africa" ? "Neutral colours" : "Comfortable",
        whatToCarry: at(["Water, hat", "Jacket, camera", "Passport copy", "Walking shoes"], d),
        notes: d === dayCount ? "Confirm departure transfer timings" : "",
      });
    }
  });
  return rows;
})();

export const itineraryForTrip = (tripId: string) => itinerary.filter((i) => i.tripId === tripId);

// ─────────────────────────────────────────────────────────── Trip hotels (operational bookings)

export const tripHotels: TripHotel[] = (() => {
  const r = rng(59);
  const out: TripHotel[] = [];
  plannedTrips.forEach((trip) => {
    const rows = itinerary.filter((i) => i.tripId === trip.id);
    let block: { hotel: string; city: string; from: string; to: string } | null = null;
    const flush = () => {
      if (!block) return;
      const master = hotels.find((h) => h.name === block!.hotel)!;
      out.push({
        id: `KV-TH-${pad(4000 + out.length)}`,
        tripId: trip.id,
        hotelId: master.id,
        hotel: master.name,
        city: master.city,
        country: master.country,
        destination: master.destination,
        checkIn: block.from,
        checkOut: dateStr(new Date(block.to), 1),
        nights: Math.max(1, Math.round((new Date(block.to).getTime() - new Date(block.from).getTime()) / 86400000) + 1),
        rooms: Math.ceil(trip.guests / 2),
        guests: trip.guests,
        mealPlan: at(["Bed & breakfast", "Half board", "Full board"], out.length),
        contact: master.phone,
        confirmation: `${master.destination.slice(0, 2).toUpperCase()}-${Math.floor(r() * 899999) + 100000}`,
        status: r() > 0.82 ? "Awaiting confirmation" : "Confirmed",
      });
      block = null;
    };
    rows.forEach((row) => {
      if (block && block.hotel === row.hotel) block.to = row.date;
      else {
        flush();
        block = { hotel: row.hotel, city: row.city, from: row.date, to: row.date };
      }
    });
    flush();
  });
  return out;
})();

export const hotelsForTrip = (tripId: string) => tripHotels.filter((h) => h.tripId === tripId);

// ─────────────────────────────────────────────────────────── Flights

export const flights: Flight[] = (() => {
  const r = rng(67);
  const out: Flight[] = [];
  plannedTrips.forEach((trip, ti) => {
    const spec = specForTrip(trip);
    const airline = at(spec.airlines, ti);
    const origin = ORIGIN_AIRPORTS.find((o) => o.code === trip.originAirport)!;
    const depPast = new Date(trip.departure).getTime() < BASE.getTime();
    const retPast = new Date(trip.returnDate).getTime() < BASE.getTime();
    const num = 100 + ((ti * 37) % 800);
    out.push({
      id: `KV-F-${pad(500 + out.length)}`,
      trip: trip.id,
      direction: "Outbound",
      airline: airline.name,
      flightNumber: `${airline.code}${num}`,
      date: trip.departure,
      departure: at(["01:20", "03:45", "09:10", "13:25"], ti),
      arrival: at(["07:55", "11:30", "16:40", "21:15"], ti),
      departureAirport: origin.code,
      arrivalAirport: spec.airport,
      terminal: at(["T1", "T2", "T3"], ti),
      baggage: spec.scope === "Domestic" ? "15kg + 7kg cabin" : "2 x 23kg",
      pnr: `${at(["A", "B", "K", "R", "T"], ti)}${Math.floor(r() * 89999) + 10000}`,
      status: depPast ? "Departed" : r() > 0.92 ? "Delayed" : "Scheduled",
    });
    out.push({
      id: `KV-F-${pad(500 + out.length)}`,
      trip: trip.id,
      direction: "Return",
      airline: airline.name,
      flightNumber: `${airline.code}${num + 1}`,
      date: trip.returnDate,
      departure: at(["10:05", "14:40", "18:20", "22:50"], ti),
      arrival: at(["17:35", "22:10", "04:55", "08:30"], ti),
      departureAirport: spec.airport,
      arrivalAirport: origin.code,
      terminal: at(["T1", "T2", "T3"], ti + 1),
      baggage: spec.scope === "Domestic" ? "15kg + 7kg cabin" : "2 x 23kg",
      pnr: `${at(["A", "B", "K", "R", "T"], ti)}${Math.floor(r() * 89999) + 10000}`,
      status: retPast ? "Departed" : r() > 0.94 ? "Delayed" : "Scheduled",
    });
  });
  return out;
})();

export const flightsForTrip = (tripId: string) => flights.filter((f) => f.trip === tripId);

// ─────────────────────────────────────────────────────────── Transport

export const transports: Transport[] = (() => {
  const r = rng(71);
  const out: Transport[] = [];
  plannedTrips.forEach((trip, ti) => {
    const spec = specForTrip(trip);
    const arrivalType = at(spec.transportTypes, ti);
    const arrivalHotel = hotelInCity(spec.name, itinerary.find((i) => i.tripId === trip.id)?.city ?? spec.gatewayCity);
    const lastRow = itinerary.filter((i) => i.tripId === trip.id).at(-1);
    const departHotel = hotelInCity(spec.name, lastRow?.city ?? spec.gatewayCity);
    const legs = [
      {
        label: "Arrival transfer",
        type: arrivalType,
        pickup: `${spec.airportName} (${spec.airport})`,
        drop: `${arrivalHotel.name}, ${arrivalHotel.city}`,
        date: trip.departure,
        meeting: "Arrivals hall, exit gate",
      },
      {
        label: "Departure transfer",
        type: at(spec.transportTypes, ti + 1),
        pickup: `${departHotel.name}, ${departHotel.city}`,
        drop: `${spec.airportName} (${spec.airport})`,
        date: trip.returnDate,
        meeting: "Hotel lobby",
      },
    ];
    legs.forEach((leg) => {
      const vehicles = VEHICLES[leg.type] ?? VEHICLES["Coach"]!;
      out.push({
        id: `KV-TR-${pad(600 + out.length)}`,
        trip: trip.id,
        leg: leg.label,
        type: leg.type,
        vehicle: at(vehicles, ti + out.length),
        driver: at(spec.drivers, ti + out.length),
        driverContact: phone(spec.dial, r),
        pickup: leg.pickup,
        drop: leg.drop,
        route: `${leg.pickup} → ${leg.drop}`,
        meetingPoint: leg.meeting,
        date: leg.date,
        time: at(["06:30", "09:00", "13:15", "17:45"], ti + out.length),
        status: new Date(leg.date).getTime() < BASE.getTime() ? "Completed" : "Scheduled",
      });
    });
  });
  return out;
})();

export const transportForTrip = (tripId: string) => transports.filter((t) => t.trip === tripId);

// ─────────────────────────────────────────────────────────── Tour managers

export const tourManagers: TourManager[] = managerNames.map((n, i) => ({
  id: `KV-M-${pad(10 + i, 3)}`,
  name: n,
  mobile: `+91 98${pad(100000 + i * 137, 6)}`,
  email: `${n.toLowerCase().replace(/ /g, ".")}@karevoyage.com`,
  languages: ["English, Hindi", "English, Hindi, German", "English, Marathi", "English, Hindi, Arabic", "English, Gujarati", "English, Malayalam"][i]!,
  experience: 4 + i * 2,
  availability: (["Available", "On Trip", "Available", "On Leave", "On Trip", "Available"] as const)[i]!,
  assignedTrips: trips.filter((t) => t.tourManager === n && t.status !== "Completed").length,
  status: "Active",
}));

// ─────────────────────────────────────────────────────────── Bookings & payments

interface Ledger {
  booking: Booking;
  payment: Payment;
}

const ledger: Ledger[] = (() => {
  const r = rng(83);
  const out: Ledger[] = [];
  trips.forEach((trip, ti) => {
    if (trip.status === "Cancelled") return;
    const tour = tourByName.get(trip.tour);
    const base = tour ? tour.startingPrice : 120000;
    (tripRoster[trip.id] ?? []).forEach((gid, gi) => {
      const guest = guestById.get(gid)!;
      const travellers = 1 + (gi % 3 === 0 ? 1 : 0);
      const total = (base + Math.floor(r() * 8) * 5000) * travellers;
      const discount = r() > 0.7 ? Math.floor(r() * 5) * 2500 : 0;
      const maxRedeem = Math.floor((total * LOYALTY_CONFIG.maxRedemptionPct) / 100);
      const rewardsUsed = guest.points > 5000 && r() > 0.72 ? Math.min(maxRedeem, Math.floor(r() * 8) * 1000) : 0;
      const net = total - discount - rewardsUsed;
      const departed = new Date(trip.departure).getTime() < BASE.getTime();
      const ratio = departed ? 1 : r();
      const paid =
        ratio > 0.72 ? net : ratio < 0.12 ? 0 : Math.round((net * (0.2 + ratio * 0.55)) / 1000) * 1000;
      const due = net - paid;
      const bookingId = `KV-B-${pad(7000 + out.length)}`;
      const dueDays = Math.round((new Date(trip.departure).getTime() - BASE.getTime()) / 86400000) - 21;
      out.push({
        booking: {
          id: bookingId,
          guestId: guest.id,
          guest: guest.name,
          trip: trip.id,
          tour: trip.tour,
          destination: trip.destination,
          bookingDate: dateStr(new Date(trip.departure), -(40 + Math.floor(r() * 90))),
          travellers,
          amount: total,
          source: at(["Mobile App", "PWA", "Call Centre", "Referral", "Walk-in"], ti + gi),
          status: trip.status === "Draft" ? "Provisional" : "Confirmed",
        },
        payment: {
          id: `KV-P-${pad(9000 + out.length)}`,
          tripId: trip.id,
          tour: trip.tour,
          destination: trip.destination,
          guestId: guest.id,
          guest: guest.name,
          bookingId,
          totalCost: total,
          discount,
          rewardsUsed,
          netPayable: net,
          paid,
          due,
          dueDate: dateStr(BASE, dueDays),
          lastPaymentDate: paid > 0 ? dateStr(BASE, -Math.floor(r() * 60)) : "",
          mode: paid > 0 ? at(["Bank Transfer", "UPI", "Card", "Cheque", "Cash"], ti + gi) : "",
          reference: paid > 0 ? `REF${Math.floor(r() * 899999) + 100000}` : "",
          receipt: paid > 0 && r() > 0.25 ? "Uploaded" : "Missing",
          status: due === 0 ? "Paid" : paid === 0 ? "Pending" : "Partial",
        },
      });
    });
  });
  return out;
})();

export const bookings: Booking[] = ledger.map((l) => l.booking);
export const payments: Payment[] = ledger.map((l) => l.payment);

export const paymentsForTrip = (tripId: string) => payments.filter((p) => p.tripId === tripId);
export const paymentsForGuest = (guestId: string) => payments.filter((p) => p.guestId === guestId);
export const bookingsForGuest = (guestId: string) => bookings.filter((b) => b.guestId === guestId);

export const transactions: Transaction[] = (() => {
  const r = rng(89);
  const out: Transaction[] = [];
  payments.forEach((p) => {
    if (p.paid <= 0 || out.length >= 420) return;
    const parts = p.due === 0 ? 2 : 1;
    for (let k = 0; k < parts; k++) {
      const amount = k === 0 ? Math.round(p.paid * (parts === 1 ? 1 : 0.4)) : p.paid - Math.round(p.paid * 0.4);
      out.push({
        id: `TXN-${pad(50000 + out.length, 6)}`,
        trip: p.tripId,
        guest: p.guest,
        guestId: p.guestId,
        bookingId: p.bookingId,
        date: dateStr(new Date(p.dueDate), -(20 + k * 25)),
        amount,
        method: p.mode || "Bank Transfer",
        reference: `${p.reference || "REF000000"}-${k + 1}`,
        status: "Paid",
        receipt: p.receipt,
        invoice: r() > 0.3 ? "Uploaded" : "Missing",
      });
    }
  });
  return out;
})();

// ─────────────────────────────────────────────────────────── Documents

export const documents: DocumentRow[] = (() => {
  const r = rng(97);
  const out: DocumentRow[] = [];
  plannedTrips.forEach((trip) => {
    const intl = trip.scope === "International";
    (tripRoster[trip.id] ?? []).forEach((gid) => {
      const guest = guestById.get(gid)!;
      const types = intl
        ? ["Passport", "Visa", "Travel Insurance", "Flight Ticket"]
        : ["Photo ID", "Travel Insurance", "Flight Ticket"];
      types.forEach((type) => {
        if (type !== "Passport" && r() > 0.55) return;
        const expOffset =
          type === "Passport"
            ? Math.round((new Date(guest.passportExpiry).getTime() - BASE.getTime()) / 86400000)
            : Math.round((new Date(trip.returnDate).getTime() - BASE.getTime()) / 86400000) + 30;
        const status: DocumentRow["status"] =
          expOffset < 0 ? "Expired" : expOffset < 90 ? "Expiring Soon" : at(["Verified", "Verified", "Uploaded", "Pending", "Rejected"] as const, out.length);
        out.push({
          id: `KV-DOC-${pad(2000 + out.length)}`,
          guestId: guest.id,
          guest: guest.name,
          trip: trip.id,
          tour: trip.tour,
          departure: trip.departure,
          type,
          name: `${type.toLowerCase().replace(/ /g, "-")}-${guest.id}.pdf`,
          uploadedDate: dateStr(new Date(trip.departure), -(30 + Math.floor(r() * 60))),
          expiry: dateStr(BASE, expOffset),
          status,
          verification:
            status === "Verified" ? "Verified by Abdul Barik" : status === "Rejected" ? "Rejected — unclear scan" : "Awaiting review",
          notes: "",
        });
      });
    });
  });
  return out;
})();

export const documentsForTrip = (tripId: string) => documents.filter((d) => d.trip === tripId);
export const documentsForGuest = (guestId: string) => documents.filter((d) => d.guestId === guestId);

// ─────────────────────────────────────────────────────────── Loyalty (driven by LOYALTY_CONFIG)

export const membershipTiers: MembershipTier[] = LOYALTY_CONFIG.tiers.map((t) => ({
  id: t.id,
  name: t.name,
  qualification: `${t.qualifyingTrips} completed trip${t.qualifyingTrips > 1 ? "s" : ""} or ${t.qualifyingPoints.toLocaleString("en-IN")} points`,
  points: t.qualifyingPoints,
  benefits: t.benefits,
  status: t.status,
  sortOrder: t.sortOrder,
  effectiveDate: t.effectiveDate,
}));

export const rewardRules: RewardRule[] = loyaltyRules;

export const rewardTxns: RewardTxn[] = (() => {
  const r = rng(101);
  const out: RewardTxn[] = [];
  guests.forEach((g, gi) => {
    if (gi % 2 === 1) return;
    const earned = dateStr(BASE, -Math.floor(r() * 400));
    out.push({
      id: `KV-R-${pad(3000 + out.length)}`,
      guestId: g.id,
      guest: g.name,
      date: g.createdDate,
      type: "Joining Bonus",
      trip: "",
      points: LOYALTY_CONFIG.joiningBonusPoints,
      status: "Available",
      expiry: dateStr(new Date(g.createdDate), LOYALTY_CONFIG.pointExpiryMonths * 30),
      reference: `JB${pad(gi, 5)}`,
    });
    const p = paymentsForGuest(g.id)[0];
    if (p) {
      const trip = tripById.get(p.tripId)!;
      const ratePct =
        trip.scope === "Domestic" ? LOYALTY_CONFIG.earnRates.domesticPct : LOYALTY_CONFIG.earnRates.internationalPct;
      out.push({
        id: `KV-R-${pad(3000 + out.length)}`,
        guestId: g.id,
        guest: g.name,
        date: earned,
        type: "Earned",
        trip: trip.id,
        points: Math.round((p.netPayable * ratePct) / 100),
        status: "Available",
        expiry: dateStr(new Date(earned), LOYALTY_CONFIG.pointExpiryMonths * 30),
        reference: `TR${pad(gi, 5)}`,
      });
      if (p.rewardsUsed > 0) {
        out.push({
          id: `KV-R-${pad(3000 + out.length)}`,
          guestId: g.id,
          guest: g.name,
          date: earned,
          type: "Redeemed",
          trip: trip.id,
          points: -p.rewardsUsed,
          status: "Used",
          expiry: "",
          reference: `RD${pad(gi, 5)}`,
        });
      }
    }
  });
  return out;
})();

export const referrals: Referral[] = (() => {
  const r = rng(103);
  return Array.from({ length: 90 }, (_, i) => {
    const referrer = at(guests, i * 3);
    const referred = at(guests, i * 3 + 41);
    const status = at(["Invited", "Registered", "Booked", "Travel Completed", "Reward Credited", "Invalid"] as const, i);
    const credited = status === "Reward Credited" || status === "Travel Completed";
    const booking = status === "Booked" || credited ? bookingsForGuest(referred.id)[0] : undefined;
    return {
      id: `KV-RF-${pad(400 + i)}`,
      referrer: referrer.name,
      referral: referred.name,
      date: dateStr(BASE, -Math.floor(r() * 300)),
      status,
      booking: booking?.id ?? "",
      trip: booking?.trip ?? "",
      reward: credited ? LOYALTY_CONFIG.referralRewardPoints : 0,
      rewardStatus: status === "Reward Credited" ? "Credited" : credited ? "Pending" : "Not Applicable",
    } satisfies Referral;
  });
})();

export const wishlist: WishlistRow[] = (() => {
  const r = rng(107);
  return Array.from({ length: 120 }, (_, i) => {
    const tour = at(tours, i * 5);
    return {
      id: `KV-W-${pad(800 + i)}`,
      guest: at(guests, i * 7).name,
      tour: tour.name,
      destination: tour.destination,
      savedDate: dateStr(BASE, -Math.floor(r() * 250)),
      status: at(["Saved", "Saved", "Saved", "Booked", "Removed"] as const, i),
    };
  });
})();

// ─────────────────────────────────────────────────────────── Community

export const communityPosts: CommunityPost[] = (() => {
  const r = rng(109);
  return Array.from({ length: 110 }, (_, i) => {
    const trip = at(plannedTrips.length ? plannedTrips : trips, i * 3);
    return {
      id: `KV-C-${pad(5000 + i)}`,
      guest: at(guestsOnTrip(trip.id).length ? guestsOnTrip(trip.id) : guests, i).name,
      type: at(["Post", "Story", "Photo", "Recommendation", "Review"] as const, i),
      destination: trip.destination,
      trip: trip.id,
      createdDate: dateStr(BASE, -Math.floor(r() * 180)),
      likes: Math.floor(r() * 320),
      comments: Math.floor(r() * 45),
      status: at(["Published", "Published", "Published", "Pending", "Hidden", "Rejected"] as const, i),
      reported: i % 11 === 0,
      featured: i % 13 === 0,
    };
  });
})();

export const moderationQueue: ModerationRow[] = (() => {
  const r = rng(113);
  return Array.from({ length: 18 }, (_, i) => {
    const post = at(communityPosts, i * 6);
    return {
      id: `MOD-${pad(100 + i, 3)}`,
      post: post.id,
      author: post.guest,
      reporter: at(guests, i * 9 + 5).name,
      reason: at(["Spam", "Inappropriate content", "Misleading recommendation", "Personal information", "Harassment"], i),
      date: dateStr(BASE, -Math.floor(r() * 30)),
      status: at(["Open", "Open", "Resolved", "Escalated"] as const, i),
    };
  });
})();

// ─────────────────────────────────────────────────────────── CMS content

export const contentRows: ContentRow[] = (() => {
  const sections = [
    "Home Banner", "Hero Section", "Editorial Collection", "Travel Interest", "Featured Tour",
    "Promotional Card", "Destination Content", "Testimonial", "FAQ", "Travel Tip",
    "Community Featured", "Social Link", "Footer Content",
  ];
  return sections.flatMap((section, si) =>
    Array.from({ length: 3 }, (_, i) => ({
      id: `KV-CN-${pad(si * 3 + i + 1, 3)}`,
      section,
      title: `${section} ${i + 1}`,
      subtitle: at(["Journeys made effortless", "Curated for you", "Travel with care", "Discover more"], si + i),
      cta: at(["Explore", "Book now", "Read more", "View collection"], si + i),
      link: `/explore/${section.toLowerCase().replace(/ /g, "-")}`,
      order: i + 1,
      startDate: dateStr(BASE, -30),
      endDate: dateStr(BASE, 120),
      audience: at(["All Guests", "Gold+", "Platinum+", "Upcoming travellers"], si + i),
      status: at(["Published", "Published", "Draft", "Review", "Unpublished"] as const, si + i),
    })),
  );
})();

// ─────────────────────────────────────────────────────────── Notifications
// CHANNEL (how it is delivered) is kept strictly separate from PURPOSE (why).

export const NOTIFICATION_CHANNELS = ["SMS", "Email", "Push", "In-app"] as const;
export const NOTIFICATION_PURPOSES = ["Travel", "Payment", "Loyalty", "Community", "Promotion", "System"] as const;

export const notifications: NotificationRow[] = (() => {
  const r = rng(131);
  const templates: { title: string; purpose: (typeof NOTIFICATION_PURPOSES)[number] }[] = [
    { title: "Your journey departs in 7 days", purpose: "Travel" },
    { title: "Final itinerary is ready to view", purpose: "Travel" },
    { title: "Balance payment due in 14 days", purpose: "Payment" },
    { title: "Payment received — receipt attached", purpose: "Payment" },
    { title: "Reward points expiring next month", purpose: "Loyalty" },
    { title: "You have reached Platinum tier", purpose: "Loyalty" },
    { title: "Your travel story was featured", purpose: "Community" },
    { title: "New Japan departures now open", purpose: "Promotion" },
    { title: "Complete your traveller profile", purpose: "System" },
    { title: "Passport expiring — action needed", purpose: "Travel" },
  ];
  return Array.from({ length: 60 }, (_, i) => {
    const t = at(templates, i);
    const sent = Math.floor(r() * 4000);
    return {
      id: `KV-N-${pad(600 + i)}`,
      title: t.title,
      channel: at(NOTIFICATION_CHANNELS, i),
      purpose: t.purpose,
      audience: at(
        ["All Guests", "Platinum Tier", "Guests with Upcoming Trips", "Guests with Expiring Rewards", "Incomplete Profiles"],
        i,
      ),
      scheduled: dateStr(BASE, Math.floor(r() * 60) - 30),
      sent,
      opened: Math.floor(sent * (0.2 + r() * 0.5)),
      status: at(["Draft", "Scheduled", "Sent", "Sent", "Cancelled"] as const, i),
    } satisfies NotificationRow;
  });
})();

// ─────────────────────────────────────────────────────────── Admin

export const importRuns: ImportRun[] = (() => {
  const r = rng(137);
  return Array.from({ length: 24 }, (_, i) => {
    const rows = 20 + Math.floor(r() * 300);
    const errors = Math.floor(r() * 12);
    return {
      id: `IMP-${pad(900 + i)}`,
      module: at(["Guests", "Tours", "Trips", "Itinerary", "Hotels", "Flights", "Payments", "Documents", "Rewards", "Referrals"], i),
      date: dateStr(BASE, -Math.floor(r() * 60)),
      rows,
      success: rows - errors,
      errors,
      importedBy: at(["Abdul Barik", "Sneha Rao", "Amit Mehta", "Priya Nair"], i),
      status: errors === 0 ? "Completed" : "Completed with errors",
    } satisfies ImportRun;
  });
})();

export const users: UserRow[] = [
  { id: "U-001", name: "Abdul Barik", email: "abdul@karevoyage.com", role: "Super Admin", lastLogin: "2026-08-26", status: "Active" },
  { id: "U-002", name: "Sneha Rao", email: "sneha@karevoyage.com", role: "Operations", lastLogin: "2026-08-25", status: "Active" },
  { id: "U-003", name: "Amit Mehta", email: "amit@karevoyage.com", role: "CRM", lastLogin: "2026-08-26", status: "Active" },
  { id: "U-004", name: "Priya Nair", email: "priya@karevoyage.com", role: "Finance", lastLogin: "2026-08-24", status: "Active" },
  { id: "U-005", name: "Rahul Verma", email: "rahul@karevoyage.com", role: "Content Manager", lastLogin: "2026-08-22", status: "Active" },
  { id: "U-006", name: "Lata Menon", email: "lata@karevoyage.com", role: "Community Moderator", lastLogin: "2026-08-23", status: "Active" },
  { id: "U-007", name: "Imran Sheikh", email: "imran@karevoyage.com", role: "Support", lastLogin: "2026-08-20", status: "Invited" },
  { id: "U-008", name: "Kavita Iyer", email: "kavita@karevoyage.com", role: "Reporting", lastLogin: "2026-08-19", status: "Active" },
];

export const roleMatrix = [
  { role: "Super Admin", modules: "Everything" },
  { role: "Admin", modules: "All operational modules, no user management" },
  { role: "Operations", modules: "Trips, Itineraries, Hotels, Flights, Transport, Tour Managers, Documents" },
  { role: "CRM", modules: "Guests, Profiles, Membership, Rewards, Referrals" },
  { role: "Finance", modules: "Payments, Transactions, Invoices, Receipts, Reports" },
  { role: "Content Manager", modules: "Tours, Destinations, Content, Notifications" },
  { role: "Community Moderator", modules: "Community posts, Reports, Moderation" },
  { role: "Support", modules: "Guests (read), Trips (read), Documents, Support requests" },
  { role: "Reporting", modules: "All reports, read-only" },
];

export const auditLog: AuditRow[] = (() => {
  const r = rng(139);
  const users = ["Abdul Barik", "Sneha Rao", "Amit Mehta", "Priya Nair", "Rahul Verma"];
  const out: AuditRow[] = [];

  plannedTrips.forEach((trip, ti) => {
    const spec = specForTrip(trip);
    const days = itinerary.filter((i) => i.tripId === trip.id);
    const stays = tripHotels.filter((h) => h.tripId === trip.id);
    const legs = flights.filter((f) => f.trip === trip.id);
    const paid = payments.filter((p) => p.tripId === trip.id && p.paid > 0);
    const roster = tripRoster[trip.id] ?? [];
    const dep = new Date(trip.departure).getTime();

    /** Days before departure, never in the future. */
    const when = (offset: number) => {
      const t = Math.min(dep - offset * 86400000, BASE.getTime());
      return dateStr(new Date(t), 0);
    };

    const events: { module: string; action: string; old: string; now: string; offset: number }[] = [
      { module: "Trips", action: "Created journey", old: "—", now: `${trip.tour} · ${trip.departure}`, offset: 75 },
      { module: "Trips", action: "Assigned tour manager", old: "Unassigned", now: trip.tourManager, offset: 60 },
      ...(stays[0]
        ? [{ module: "Hotels", action: `Confirmed stay at ${stays[0].hotel}`, old: "Awaiting confirmation", now: `Confirmed · ${stays[0].confirmation}`, offset: 45 }]
        : []),
      ...(legs[0]
        ? [{ module: "Flights", action: `Ticketed ${legs[0].airline} ${legs[0].flightNumber}`, old: "Held", now: `PNR ${legs[0].pnr}`, offset: 40 }]
        : []),
      ...(days[0]
        ? [{ module: "Itinerary", action: `Updated Day ${days[Math.min(2, days.length - 1)]!.day} plan`, old: "Leisure day", now: days[Math.min(2, days.length - 1)]!.activity, offset: 30 }]
        : []),
      { module: "Guests", action: "Updated rooming list", old: `${Math.max(0, roster.length - 2)} travellers`, now: `${roster.length} travellers`, offset: 24 },
      ...(paid[0]
        ? [{ module: "Payments", action: `Recorded payment from ${paid[0].guest}`, old: "Pending", now: `₹${paid[0].paid.toLocaleString("en-IN")}`, offset: 18 }]
        : []),
      { module: "Documents", action: "Verified passport batch", old: "Awaiting review", now: `${Math.max(1, Math.round(roster.length * 0.7))} verified`, offset: 12 },
      { module: "Transport", action: `Booked arrival transfer · ${spec.gatewayCity}`, old: "Not arranged", now: "Scheduled", offset: 8 },
    ];

    events.forEach((e, ei) => {
      out.push({
        id: `AUD-${pad(1000 + out.length)}`,
        user: at(users, ti + ei),
        action: e.action,
        module: e.module,
        record: trip.id,
        date: when(e.offset + Math.floor(r() * 3)),
        oldValue: e.old,
        newValue: e.now,
      });
    });
  });

  return out.sort((a, b) => (a.date < b.date ? 1 : a.date > b.date ? -1 : 0));
})();

export const activityForTrip = (tripId: string) => auditLog.filter((a) => a.record === tripId);

export const recentActivity = auditLog.slice(0, 10);


export const hasItinerary = (tripId: string) => plannedIds.has(tripId);

export const dashboardStats = {
  totalGuests: guests.length,
  upcomingTrips: trips.filter((t) => t.status === "Upcoming" || t.status === "Confirmed").length,
  activeTrips: trips.filter((t) => t.status === "Active").length,
  pendingPayments: payments.filter((p) => p.due > 0).length,
  documentsAttention: documents.filter((d) => d.status === "Expired" || d.status === "Expiring Soon" || d.status === "Rejected").length,
  openSupport: 7,
  pendingReferrals: referrals.filter((r) => r.rewardStatus === "Pending").length,
  pointsLiability: rewardTxns.filter((r) => r.status === "Available").reduce((s, r) => s + Math.max(r.points, 0), 0),
};
