/** Convert mongoose lean docs / subdocs so API responses use `id` like Prisma. */
export function toPlain<T = any>(value: T): any {
  if (value == null) return value;
  if (value instanceof Date) return value;
  if (Array.isArray(value)) return value.map((item) => toPlain(item));
  if (typeof value !== "object") return value;

  const obj = value as Record<string, any>;
  if (typeof obj.toObject === "function") {
    return toPlain(obj.toObject({ virtuals: true }));
  }

  const out: Record<string, any> = {};
  for (const [key, val] of Object.entries(obj)) {
    if (key === "__v") continue;
    if (key === "_id") {
      out.id = typeof val === "object" && val !== null ? String((val as any).toString?.() ?? val) : val;
      continue;
    }
    out[key] = toPlain(val);
  }
  return out;
}

export function toNumber(value: number | string | null | undefined) {
  if (value == null) return 0;
  return typeof value === "number" ? value : Number(value);
}

function normalizeCity(city: any) {
  if (!city) return undefined;
  const plain = toPlain(city);
  return { ...plain, name: plain.nameEn };
}

function normalizeMedia(list: any[] | undefined) {
  if (!list) return list;
  return list.map((item) => toPlain(item));
}

export function serializeProperty(property: any) {
  const plain = toPlain(property);
  const city =
    plain.city ??
    (plain.cityId && typeof plain.cityId === "object" ? normalizeCity(plain.cityId) : undefined);
  const cityId =
    typeof plain.cityId === "object" && plain.cityId
      ? plain.cityId.id ?? plain.cityId._id
      : plain.cityId;

  const owner =
    plain.owner ??
    (plain.ownerId && typeof plain.ownerId === "object" ? toPlain(plain.ownerId) : undefined);
  const ownerId =
    typeof plain.ownerId === "object" && plain.ownerId
      ? plain.ownerId.id ?? plain.ownerId._id
      : plain.ownerId;

  return {
    ...plain,
    cityId,
    ownerId,
    city: city ? normalizeCity(city) : city,
    owner,
    images: normalizeMedia(plain.images),
    videos: normalizeMedia(plain.videos),
    blockedDates: Array.isArray(plain.blockedDates) ? plain.blockedDates : [],
    basePriceTnd: toNumber(plain.basePriceTnd),
    cleaningFeeTnd: toNumber(plain.cleaningFeeTnd),
    title: plain.titleEn,
    description: plain.descriptionEn,
  };
}

export function serializeBooking(booking: any) {
  const plain = toPlain(booking);
  const property =
    plain.property ??
    (plain.propertyId && typeof plain.propertyId === "object"
      ? serializeProperty(plain.propertyId)
      : undefined);
  const propertyId =
    typeof plain.propertyId === "object" && plain.propertyId
      ? plain.propertyId.id ?? plain.propertyId._id
      : plain.propertyId;

  const customer =
    plain.customer ??
    (plain.customerId && typeof plain.customerId === "object" ? toPlain(plain.customerId) : undefined);
  const customerId =
    typeof plain.customerId === "object" && plain.customerId
      ? plain.customerId.id ?? plain.customerId._id
      : plain.customerId;

  const owner =
    plain.owner ??
    (plain.ownerId && typeof plain.ownerId === "object" ? toPlain(plain.ownerId) : undefined);
  const ownerId =
    typeof plain.ownerId === "object" && plain.ownerId
      ? plain.ownerId.id ?? plain.ownerId._id
      : plain.ownerId;

  return {
    ...plain,
    propertyId,
    customerId,
    ownerId,
    customer,
    owner,
    exchangeRateRate: toNumber(plain.exchangeRateRate),
    subtotalTnd: toNumber(plain.subtotalTnd),
    cleaningFeeTnd: toNumber(plain.cleaningFeeTnd),
    platformFeeTnd: toNumber(plain.platformFeeTnd),
    taxesTnd: toNumber(plain.taxesTnd),
    discountTnd: toNumber(plain.discountTnd),
    totalTnd: toNumber(plain.totalTnd),
    totalLyd: toNumber(plain.totalLyd),
    ownerPayoutTnd: toNumber(plain.ownerPayoutTnd),
    walletPaidLyd: toNumber(plain.walletPaidLyd),
    pointsEarned: toNumber(plain.pointsEarned),
    pointsRedeemed: toNumber(plain.pointsRedeemed),
    pointsDiscountTnd: toNumber(plain.pointsDiscountTnd),
    refundLyd: toNumber(plain.refundLyd),
    refundPercent: toNumber(plain.refundPercent),
    payment: plain.payment
      ? { ...toPlain(plain.payment), amount: toNumber(plain.payment.amount) }
      : null,
    invoice: plain.invoice
      ? {
          ...toPlain(plain.invoice),
          total: toNumber(plain.invoice.total),
          nightlyRateTnd: plain.invoice.nightlyRateTnd != null ? toNumber(plain.invoice.nightlyRateTnd) : undefined,
          subtotalTnd: plain.invoice.subtotalTnd != null ? toNumber(plain.invoice.subtotalTnd) : undefined,
          cleaningFeeTnd: plain.invoice.cleaningFeeTnd != null ? toNumber(plain.invoice.cleaningFeeTnd) : undefined,
          platformFeeTnd: plain.invoice.platformFeeTnd != null ? toNumber(plain.invoice.platformFeeTnd) : undefined,
          taxesTnd: plain.invoice.taxesTnd != null ? toNumber(plain.invoice.taxesTnd) : undefined,
          discountTnd: plain.invoice.discountTnd != null ? toNumber(plain.invoice.discountTnd) : undefined,
          totalTnd: plain.invoice.totalTnd != null ? toNumber(plain.invoice.totalTnd) : undefined,
          totalLyd: plain.invoice.totalLyd != null ? toNumber(plain.invoice.totalLyd) : undefined,
          exchangeRateRate:
            plain.invoice.exchangeRateRate != null ? toNumber(plain.invoice.exchangeRateRate) : undefined,
        }
      : null,
    property: property ? serializeProperty(property) : undefined,
  };
}
