import type { RowDataPacket } from "mysql2/promise";
import { createId } from "@/db/ids";
import { dualWritePropertyUpdateDoc, dualWritePropertyUpsert } from "@/db/dualWrite";
import { connectMysql, mysqlPool, sqlExecute, sqlQuery, withMysqlTxn } from "./pool";
import { cityRowToApi, findCityByIdMysql, type CityRow } from "./cities";

export type PropertyMedia = { id: string; url: string; sortOrder: number; createdAt?: Date };
export type PropertyRow = {
  id: string;
  ownerId: string;
  cityId: string;
  titleAr: string;
  titleEn: string;
  slug: string;
  descriptionAr: string;
  descriptionEn: string;
  address: string;
  latitude: number | null;
  longitude: number | null;
  status: string;
  bedrooms: number;
  bathrooms: number;
  maxGuests: number;
  wifi: boolean;
  parking: boolean;
  airConditioning: boolean;
  kitchen: boolean;
  hospitalNearby: boolean;
  universityNearby: boolean;
  petFriendly: boolean;
  instantBooking: boolean;
  basePriceTnd: number;
  cleaningFeeTnd: number;
  checkInTime: string;
  checkOutTime: string;
  cancellationPolicy: string;
  houseRules: string | null;
  featured: boolean;
  deletedAt: Date | null;
  createdAt: Date;
  updatedAt: Date;
  images: PropertyMedia[];
  videos: PropertyMedia[];
  blockedDates: string[];
};

export type PropertyListFilter = {
  ids?: string[];
  cityIds?: string[];
  ownerId?: string;
  status?: string;
  guests?: number;
  instantBooking?: boolean;
  featured?: boolean;
  wifi?: boolean;
  parking?: boolean;
  minPrice?: number;
  maxPrice?: number;
  excludeIds?: string[];
  take?: number;
  skip?: number;
};

async function ensure() {
  try {
    mysqlPool();
  } catch {
    await connectMysql();
  }
}

function mapProperty(r: RowDataPacket): Omit<PropertyRow, "images" | "videos" | "blockedDates"> {
  return {
    id: String(r.id),
    ownerId: String(r.owner_id),
    cityId: String(r.city_id),
    titleAr: String(r.title_ar),
    titleEn: String(r.title_en),
    slug: String(r.slug),
    descriptionAr: String(r.description_ar),
    descriptionEn: String(r.description_en),
    address: String(r.address),
    latitude: r.latitude == null ? null : Number(r.latitude),
    longitude: r.longitude == null ? null : Number(r.longitude),
    status: String(r.status),
    bedrooms: Number(r.bedrooms),
    bathrooms: Number(r.bathrooms),
    maxGuests: Number(r.max_guests),
    wifi: Boolean(r.wifi),
    parking: Boolean(r.parking),
    airConditioning: Boolean(r.air_conditioning),
    kitchen: Boolean(r.kitchen),
    hospitalNearby: Boolean(r.hospital_nearby),
    universityNearby: Boolean(r.university_nearby),
    petFriendly: Boolean(r.pet_friendly),
    instantBooking: Boolean(r.instant_booking),
    basePriceTnd: Number(r.base_price_tnd),
    cleaningFeeTnd: Number(r.cleaning_fee_tnd),
    checkInTime: String(r.check_in_time || "15:00"),
    checkOutTime: String(r.check_out_time || "11:00"),
    cancellationPolicy: String(r.cancellation_policy || ""),
    houseRules: r.house_rules == null ? null : String(r.house_rules),
    featured: Boolean(r.featured),
    deletedAt: r.deleted_at ? new Date(r.deleted_at) : null,
    createdAt: new Date(r.created_at),
    updatedAt: new Date(r.updated_at),
  };
}

function toIsoDay(d: Date | string) {
  if (typeof d === "string") return d.slice(0, 10);
  const y = d.getUTCFullYear();
  const m = String(d.getUTCMonth() + 1).padStart(2, "0");
  const day = String(d.getUTCDate()).padStart(2, "0");
  return `${y}-${m}-${day}`;
}

async function loadMedia(propertyIds: string[]) {
  const images = new Map<string, PropertyMedia[]>();
  const videos = new Map<string, PropertyMedia[]>();
  const blocked = new Map<string, string[]>();
  if (propertyIds.length === 0) return { images, videos, blocked };
  const ph = propertyIds.map(() => "?").join(",");

  const imgRows = await sqlQuery<RowDataPacket[]>(
    `SELECT * FROM property_images WHERE property_id IN (${ph}) ORDER BY sort_order ASC, created_at ASC`,
    propertyIds,
  );
  for (const r of imgRows) {
    const pid = String(r.property_id);
    const list = images.get(pid) || [];
    list.push({
      id: String(r.id),
      url: String(r.url),
      sortOrder: Number(r.sort_order ?? 0),
      createdAt: r.created_at ? new Date(r.created_at) : undefined,
    });
    images.set(pid, list);
  }

  const vidRows = await sqlQuery<RowDataPacket[]>(
    `SELECT * FROM property_videos WHERE property_id IN (${ph}) ORDER BY sort_order ASC, created_at ASC`,
    propertyIds,
  );
  for (const r of vidRows) {
    const pid = String(r.property_id);
    const list = videos.get(pid) || [];
    list.push({
      id: String(r.id),
      url: String(r.url),
      sortOrder: Number(r.sort_order ?? 0),
      createdAt: r.created_at ? new Date(r.created_at) : undefined,
    });
    videos.set(pid, list);
  }

  const blkRows = await sqlQuery<RowDataPacket[]>(
    `SELECT property_id, blocked_date FROM property_blocked_dates WHERE property_id IN (${ph})`,
    propertyIds,
  );
  for (const r of blkRows) {
    const pid = String(r.property_id);
    const list = blocked.get(pid) || [];
    list.push(toIsoDay(r.blocked_date as Date | string));
    blocked.set(pid, list);
  }

  return { images, videos, blocked };
}

async function hydrate(rows: RowDataPacket[]): Promise<PropertyRow[]> {
  const base = rows.map(mapProperty);
  const { images, videos, blocked } = await loadMedia(base.map((p) => p.id));
  return base.map((p) => ({
    ...p,
    images: images.get(p.id) || [],
    videos: videos.get(p.id) || [],
    blockedDates: (blocked.get(p.id) || []).sort(),
  }));
}

export function propertyToApi(p: PropertyRow, city?: CityRow | null) {
  return {
    _id: p.id,
    id: p.id,
    ownerId: p.ownerId,
    cityId: p.cityId,
    titleAr: p.titleAr,
    titleEn: p.titleEn,
    slug: p.slug,
    descriptionAr: p.descriptionAr,
    descriptionEn: p.descriptionEn,
    address: p.address,
    latitude: p.latitude,
    longitude: p.longitude,
    status: p.status,
    bedrooms: p.bedrooms,
    bathrooms: p.bathrooms,
    maxGuests: p.maxGuests,
    wifi: p.wifi,
    parking: p.parking,
    airConditioning: p.airConditioning,
    kitchen: p.kitchen,
    hospitalNearby: p.hospitalNearby,
    universityNearby: p.universityNearby,
    petFriendly: p.petFriendly,
    instantBooking: p.instantBooking,
    basePriceTnd: p.basePriceTnd,
    cleaningFeeTnd: p.cleaningFeeTnd,
    checkInTime: p.checkInTime,
    checkOutTime: p.checkOutTime,
    cancellationPolicy: p.cancellationPolicy,
    houseRules: p.houseRules ?? undefined,
    featured: p.featured,
    deletedAt: p.deletedAt,
    createdAt: p.createdAt,
    updatedAt: p.updatedAt,
    images: p.images.map((m) => ({
      _id: m.id,
      id: m.id,
      url: m.url,
      sortOrder: m.sortOrder,
      createdAt: m.createdAt,
    })),
    videos: p.videos.map((m) => ({
      _id: m.id,
      id: m.id,
      url: m.url,
      sortOrder: m.sortOrder,
      createdAt: m.createdAt,
    })),
    blockedDates: p.blockedDates,
    city: city ? cityRowToApi(city) : undefined,
  };
}

export async function findPropertyByIdMysql(id: string): Promise<PropertyRow | null> {
  await ensure();
  const rows = await sqlQuery<RowDataPacket[]>(
    `SELECT * FROM properties WHERE id = ? AND deleted_at IS NULL LIMIT 1`,
    [id],
  );
  if (!rows[0]) return null;
  return (await hydrate(rows))[0];
}

export async function findPropertiesByIdsMysql(ids: string[]): Promise<PropertyRow[]> {
  await ensure();
  if (ids.length === 0) return [];
  const ph = ids.map(() => "?").join(",");
  const rows = await sqlQuery<RowDataPacket[]>(
    `SELECT * FROM properties WHERE id IN (${ph}) AND deleted_at IS NULL`,
    ids,
  );
  const hydrated = await hydrate(rows);
  const byId = new Map(hydrated.map((p) => [p.id, p]));
  return ids.map((id) => byId.get(id)).filter(Boolean) as PropertyRow[];
}

export async function getBlockedDatesMysql(propertyId: string): Promise<string[]> {
  await ensure();
  const rows = await sqlQuery<RowDataPacket[]>(
    `SELECT blocked_date FROM property_blocked_dates WHERE property_id = ?`,
    [propertyId],
  );
  return rows.map((r) => toIsoDay(r.blocked_date as Date | string)).sort();
}

export async function propertyIdsBlockedOnDatesMysql(dates: string[]): Promise<string[]> {
  await ensure();
  if (dates.length === 0) return [];
  const ph = dates.map(() => "?").join(",");
  const rows = await sqlQuery<RowDataPacket[]>(
    `SELECT DISTINCT p.id
     FROM properties p
     INNER JOIN property_blocked_dates b ON b.property_id = p.id
     WHERE p.deleted_at IS NULL AND b.blocked_date IN (${ph})`,
    dates,
  );
  return rows.map((r) => String(r.id));
}

function buildListWhere(filter: PropertyListFilter) {
  const where: string[] = ["deleted_at IS NULL"];
  const params: unknown[] = [];

  if (filter.ids?.length) {
    where.push(`id IN (${filter.ids.map(() => "?").join(",")})`);
    params.push(...filter.ids);
  }
  if (filter.excludeIds?.length) {
    where.push(`id NOT IN (${filter.excludeIds.map(() => "?").join(",")})`);
    params.push(...filter.excludeIds);
  }
  if (filter.cityIds?.length) {
    where.push(`city_id IN (${filter.cityIds.map(() => "?").join(",")})`);
    params.push(...filter.cityIds);
  }
  if (filter.ownerId) {
    where.push(`owner_id = ?`);
    params.push(filter.ownerId);
  }
  if (filter.status) {
    where.push(`status = ?`);
    params.push(filter.status);
  }
  if (filter.guests) {
    where.push(`max_guests >= ?`);
    params.push(filter.guests);
  }
  if (filter.instantBooking) {
    where.push(`instant_booking = 1`);
  }
  if (filter.featured) {
    where.push(`featured = 1`);
  }
  if (filter.wifi) {
    where.push(`wifi = 1`);
  }
  if (filter.parking) {
    where.push(`parking = 1`);
  }
  if (filter.minPrice != null) {
    where.push(`base_price_tnd >= ?`);
    params.push(filter.minPrice);
  }
  if (filter.maxPrice != null) {
    where.push(`base_price_tnd <= ?`);
    params.push(filter.maxPrice);
  }

  return { whereSql: where.join(" AND "), params };
}

export async function listPropertiesMysql(
  filter: PropertyListFilter,
): Promise<{ properties: PropertyRow[]; total: number }> {
  await ensure();
  const { whereSql, params } = buildListWhere(filter);
  const take = filter.take ?? 50;
  const skip = filter.skip ?? 0;

  const countRows = await sqlQuery<RowDataPacket[]>(
    `SELECT COUNT(*) AS c FROM properties WHERE ${whereSql}`,
    params,
  );
  const total = Number(countRows[0]?.c ?? 0);

  const order = filter.ids?.length
    ? `ORDER BY created_at DESC`
    : `ORDER BY featured DESC, created_at DESC`;

  const rows = await sqlQuery<RowDataPacket[]>(
    `SELECT * FROM properties WHERE ${whereSql} ${order} LIMIT ? OFFSET ?`,
    [...params, take, skip],
  );
  let properties = await hydrate(rows);
  if (filter.ids?.length) {
    const byId = new Map(properties.map((p) => [p.id, p]));
    properties = filter.ids.map((id) => byId.get(id)).filter(Boolean) as PropertyRow[];
  }
  return { properties, total: filter.ids?.length ? properties.length : total };
}

async function replaceImages(
  propertyId: string,
  images: { url: string; sortOrder?: number }[],
) {
  await sqlExecute(`DELETE FROM property_images WHERE property_id = ?`, [propertyId]);
  const now = new Date();
  for (let i = 0; i < images.length; i++) {
    const img = images[i];
    await sqlExecute(
      `INSERT INTO property_images (id, property_id, url, sort_order, created_at) VALUES (?,?,?,?,?)`,
      [createId(), propertyId, img.url, img.sortOrder ?? i, now],
    );
  }
}

async function replaceVideos(
  propertyId: string,
  videos: { url: string; sortOrder?: number }[],
) {
  await sqlExecute(`DELETE FROM property_videos WHERE property_id = ?`, [propertyId]);
  const now = new Date();
  for (let i = 0; i < videos.length; i++) {
    const vid = videos[i];
    await sqlExecute(
      `INSERT INTO property_videos (id, property_id, url, sort_order, created_at) VALUES (?,?,?,?,?)`,
      [createId(), propertyId, vid.url, vid.sortOrder ?? i, now],
    );
  }
}

async function replaceBlockedDates(propertyId: string, dates: string[]) {
  await sqlExecute(`DELETE FROM property_blocked_dates WHERE property_id = ?`, [propertyId]);
  for (const d of dates) {
    await sqlExecute(
      `INSERT INTO property_blocked_dates (property_id, blocked_date) VALUES (?,?)`,
      [propertyId, d],
    );
  }
}

export type PropertyWriteInput = {
  ownerId: string;
  cityId: string;
  titleAr: string;
  titleEn: string;
  slug: string;
  descriptionAr: string;
  descriptionEn: string;
  address: string;
  latitude?: number | null;
  longitude?: number | null;
  bedrooms: number;
  bathrooms: number;
  maxGuests: number;
  wifi?: boolean;
  parking?: boolean;
  airConditioning?: boolean;
  kitchen?: boolean;
  hospitalNearby?: boolean;
  universityNearby?: boolean;
  petFriendly?: boolean;
  instantBooking?: boolean;
  basePriceTnd: number;
  cleaningFeeTnd?: number;
  checkInTime?: string;
  checkOutTime?: string;
  cancellationPolicy?: string;
  houseRules?: string | null;
  featured?: boolean;
  status?: string;
  images?: { url: string; sortOrder?: number }[];
  videos?: { url: string; sortOrder?: number }[];
  blockedDates?: string[];
};

export async function createPropertyMysql(input: PropertyWriteInput): Promise<PropertyRow> {
  await ensure();
  const id = createId();
  const now = new Date();
  await withMysqlTxn(async (conn) => {
    await conn.execute(
      `INSERT INTO properties (
        id, owner_id, city_id, title_ar, title_en, slug, description_ar, description_en,
        address, latitude, longitude, status, bedrooms, bathrooms, max_guests,
        wifi, parking, air_conditioning, kitchen, hospital_nearby, university_nearby,
        pet_friendly, instant_booking, base_price_tnd, cleaning_fee_tnd,
        check_in_time, check_out_time, cancellation_policy, house_rules, featured,
        deleted_at, created_at, updated_at
      ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,NULL,?,?)`,
      [
        id,
        input.ownerId,
        input.cityId,
        input.titleAr,
        input.titleEn,
        input.slug,
        input.descriptionAr,
        input.descriptionEn,
        input.address,
        input.latitude ?? null,
        input.longitude ?? null,
        input.status ?? "DRAFT",
        input.bedrooms,
        input.bathrooms,
        input.maxGuests,
        input.wifi ? 1 : 0,
        input.parking ? 1 : 0,
        input.airConditioning ? 1 : 0,
        input.kitchen ? 1 : 0,
        input.hospitalNearby ? 1 : 0,
        input.universityNearby ? 1 : 0,
        input.petFriendly ? 1 : 0,
        input.instantBooking ? 1 : 0,
        input.basePriceTnd,
        input.cleaningFeeTnd ?? 0,
        input.checkInTime || "15:00",
        input.checkOutTime || "11:00",
        input.cancellationPolicy || "Free cancellation within 48 hours.",
        input.houseRules ?? null,
        input.featured ? 1 : 0,
        now,
        now,
      ],
    );
  });
  await replaceImages(id, input.images ?? []);
  await replaceVideos(id, input.videos ?? []);
  await replaceBlockedDates(id, input.blockedDates ?? []);
  const row = await findPropertyByIdMysql(id);
  if (!row) throw new Error("failed to create property");
  await dualWritePropertyUpsert(row);
  return row;
}

export async function updatePropertyMysql(
  id: string,
  patch: Partial<PropertyWriteInput>,
): Promise<PropertyRow | null> {
  await ensure();
  const existing = await findPropertyByIdMysql(id);
  if (!existing) return null;

  const next = {
    cityId: patch.cityId ?? existing.cityId,
    titleAr: patch.titleAr ?? existing.titleAr,
    titleEn: patch.titleEn ?? existing.titleEn,
    slug: patch.slug ?? existing.slug,
    descriptionAr: patch.descriptionAr ?? existing.descriptionAr,
    descriptionEn: patch.descriptionEn ?? existing.descriptionEn,
    address: patch.address ?? existing.address,
    latitude: patch.latitude !== undefined ? patch.latitude : existing.latitude,
    longitude: patch.longitude !== undefined ? patch.longitude : existing.longitude,
    bedrooms: patch.bedrooms ?? existing.bedrooms,
    bathrooms: patch.bathrooms ?? existing.bathrooms,
    maxGuests: patch.maxGuests ?? existing.maxGuests,
    wifi: patch.wifi ?? existing.wifi,
    parking: patch.parking ?? existing.parking,
    airConditioning: patch.airConditioning ?? existing.airConditioning,
    kitchen: patch.kitchen ?? existing.kitchen,
    hospitalNearby: patch.hospitalNearby ?? existing.hospitalNearby,
    universityNearby: patch.universityNearby ?? existing.universityNearby,
    petFriendly: patch.petFriendly ?? existing.petFriendly,
    instantBooking: patch.instantBooking ?? existing.instantBooking,
    basePriceTnd: patch.basePriceTnd ?? existing.basePriceTnd,
    cleaningFeeTnd: patch.cleaningFeeTnd ?? existing.cleaningFeeTnd,
    checkInTime: patch.checkInTime ?? existing.checkInTime,
    checkOutTime: patch.checkOutTime ?? existing.checkOutTime,
    cancellationPolicy: patch.cancellationPolicy ?? existing.cancellationPolicy,
    houseRules: patch.houseRules !== undefined ? patch.houseRules : existing.houseRules,
    featured: patch.featured ?? existing.featured,
    status: patch.status ?? existing.status,
  };

  await sqlExecute(
    `UPDATE properties SET
      city_id=?, title_ar=?, title_en=?, slug=?, description_ar=?, description_en=?,
      address=?, latitude=?, longitude=?, status=?, bedrooms=?, bathrooms=?, max_guests=?,
      wifi=?, parking=?, air_conditioning=?, kitchen=?, hospital_nearby=?, university_nearby=?,
      pet_friendly=?, instant_booking=?, base_price_tnd=?, cleaning_fee_tnd=?,
      check_in_time=?, check_out_time=?, cancellation_policy=?, house_rules=?, featured=?,
      updated_at=?
     WHERE id=?`,
    [
      next.cityId,
      next.titleAr,
      next.titleEn,
      next.slug,
      next.descriptionAr,
      next.descriptionEn,
      next.address,
      next.latitude,
      next.longitude,
      next.status,
      next.bedrooms,
      next.bathrooms,
      next.maxGuests,
      next.wifi ? 1 : 0,
      next.parking ? 1 : 0,
      next.airConditioning ? 1 : 0,
      next.kitchen ? 1 : 0,
      next.hospitalNearby ? 1 : 0,
      next.universityNearby ? 1 : 0,
      next.petFriendly ? 1 : 0,
      next.instantBooking ? 1 : 0,
      next.basePriceTnd,
      next.cleaningFeeTnd,
      next.checkInTime,
      next.checkOutTime,
      next.cancellationPolicy,
      next.houseRules,
      next.featured ? 1 : 0,
      new Date(),
      id,
    ],
  );

  if (patch.images) await replaceImages(id, patch.images);
  if (patch.videos) await replaceVideos(id, patch.videos);
  if (patch.blockedDates) await replaceBlockedDates(id, patch.blockedDates);

  const row = await findPropertyByIdMysql(id);
  if (row) {
    await dualWritePropertyUpsert(row);
  }
  return row;
}

export async function softDeletePropertyMysql(id: string) {
  await ensure();
  await sqlExecute(
    `UPDATE properties SET deleted_at = ?, status = 'PAUSED', updated_at = ? WHERE id = ?`,
    [new Date(), new Date(), id],
  );
  const row = await findPropertyByIdMysql(id);
  // findPropertyById filters deleted_at IS NULL — load raw for dual-write
  const raw = await sqlQuery<RowDataPacket[]>(`SELECT * FROM properties WHERE id = ? LIMIT 1`, [id]);
  if (raw[0]) {
    const deleted = await hydrate([raw[0]]);
    await dualWritePropertyUpsert(deleted[0]);
  }
  return row;
}

/* ---- property updates ---- */

export type PropertyUpdateRow = {
  id: string;
  propertyId: string;
  ownerId: string;
  titleAr: string;
  titleEn: string;
  bodyAr: string;
  bodyEn: string;
  deletedAt: Date | null;
  createdAt: Date;
  updatedAt: Date;
};

function mapUpdate(r: RowDataPacket): PropertyUpdateRow {
  return {
    id: String(r.id),
    propertyId: String(r.property_id),
    ownerId: String(r.owner_id),
    titleAr: String(r.title_ar),
    titleEn: String(r.title_en),
    bodyAr: String(r.body_ar),
    bodyEn: String(r.body_en),
    deletedAt: r.deleted_at ? new Date(r.deleted_at) : null,
    createdAt: new Date(r.created_at),
    updatedAt: new Date(r.updated_at),
  };
}

export function propertyUpdateToApi(u: PropertyUpdateRow) {
  return {
    _id: u.id,
    id: u.id,
    propertyId: u.propertyId,
    ownerId: u.ownerId,
    titleAr: u.titleAr,
    titleEn: u.titleEn,
    bodyAr: u.bodyAr,
    bodyEn: u.bodyEn,
    deletedAt: u.deletedAt,
    createdAt: u.createdAt,
    updatedAt: u.updatedAt,
  };
}

export async function listPropertyUpdatesMysql(propertyId: string, limit = 30) {
  await ensure();
  const rows = await sqlQuery<RowDataPacket[]>(
    `SELECT * FROM property_updates
     WHERE property_id = ? AND deleted_at IS NULL
     ORDER BY created_at DESC LIMIT ?`,
    [propertyId, limit],
  );
  return rows.map(mapUpdate);
}

export async function createPropertyUpdateMysql(input: {
  propertyId: string;
  ownerId: string;
  titleAr: string;
  titleEn: string;
  bodyAr: string;
  bodyEn: string;
}) {
  await ensure();
  const id = createId();
  const now = new Date();
  await sqlExecute(
    `INSERT INTO property_updates
      (id, property_id, owner_id, title_ar, title_en, body_ar, body_en, deleted_at, created_at, updated_at)
     VALUES (?,?,?,?,?,?,?,NULL,?,?)`,
    [
      id,
      input.propertyId,
      input.ownerId,
      input.titleAr,
      input.titleEn,
      input.bodyAr,
      input.bodyEn,
      now,
      now,
    ],
  );
  const rows = await sqlQuery<RowDataPacket[]>(
    `SELECT * FROM property_updates WHERE id = ? LIMIT 1`,
    [id],
  );
  const row = mapUpdate(rows[0]);
  await dualWritePropertyUpdateDoc({
    id: row.id,
    propertyId: row.propertyId,
    ownerId: row.ownerId,
    titleAr: row.titleAr,
    titleEn: row.titleEn,
    bodyAr: row.bodyAr,
    bodyEn: row.bodyEn,
    deletedAt: row.deletedAt,
  });
  return row;
}

export async function softDeletePropertyUpdateMysql(updateId: string, propertyId: string) {
  await ensure();
  const res = await sqlExecute(
    `UPDATE property_updates SET deleted_at = ?, updated_at = ?
     WHERE id = ? AND property_id = ? AND deleted_at IS NULL`,
    [new Date(), new Date(), updateId, propertyId],
  );
  if (res.affectedRows > 0) {
    const rows = await sqlQuery<RowDataPacket[]>(
      `SELECT * FROM property_updates WHERE id = ? LIMIT 1`,
      [updateId],
    );
    if (rows[0]) {
      const row = mapUpdate(rows[0]);
      await dualWritePropertyUpdateDoc({
        id: row.id,
        propertyId: row.propertyId,
        ownerId: row.ownerId,
        titleAr: row.titleAr,
        titleEn: row.titleEn,
        bodyAr: row.bodyAr,
        bodyEn: row.bodyEn,
        deletedAt: row.deletedAt,
      });
    }
  }
  return res.affectedRows > 0;
}

export { findCityByIdMysql };
