const CATEGORY_IMPORT_PREFIX = 'public-search-category:';
const PLACE_IMPORT_PREFIX = 'public-search-place:';
const OFFERING_IMPORT_PREFIX = 'public-search-offering:';

const categories = [
  {
    id: '11111111-1111-4111-8111-111111111111',
    name: 'Toko Interior',
    slug: 'toko-interior',
    description: 'Toko perabot, furniture, kitchen set, dekorasi, dan jasa desain interior.',
    color_hex: '#2563EB',
    icon_name: 'mdiSofa',
  },
  {
    id: '22222222-2222-4222-8222-222222222222',
    name: 'Cafe Melayu',
    slug: 'cafe-melayu',
    description: 'Cafe, kedai kopi, dan kuliner khas Melayu atau Riau.',
    color_hex: '#16A34A',
    icon_name: 'mdiCoffeeOutline',
  },
  {
    id: '33333333-3333-4333-8333-333333333333',
    name: 'Bengkel Mobil',
    slug: 'bengkel-mobil',
    description: 'Bengkel servis mobil, ganti oli, tune up, mesin, ban, dan kaki-kaki.',
    color_hex: '#DC2626',
    icon_name: 'mdiCarWrench',
  },
    {
    id: '44444444-4444-4444-8444-444444444444',
    name: 'Jasa AC & Elektronik',
    slug: 'jasa-ac-elektronik',
    description: 'Teknisi AC, cuci AC, isi freon, servis elektronik rumah, dan booking jasa datang ke lokasi.',
    color_hex: '#0891B2',
    icon_name: 'mdiAirConditioner',
  },
  {
    id: '55555555-5555-4555-8555-555555555555',
    name: 'Toko Herbal & Kesehatan',
    slug: 'toko-herbal-kesehatan',
    description: 'Toko herbal, jamu, madu, produk kesehatan alami, dan edukasi hidup sehat lokal.',
    color_hex: '#65A30D',
    icon_name: 'mdiLeaf',
  },
];

const places = [
  {
    id: 'aaaaaaaa-1111-4111-8111-aaaaaaaa1111',
    name: 'Riau Interior Studio',
    categorySlug: 'toko-interior',
    short_description: 'Toko interior, desain ruangan, custom furniture, dan kitchen set dekat pusat kota.',
    full_description: 'Melayani desain interior rumah, kitchen set, lemari, partisi, sofa custom, dan konsultasi gratis. Cocok untuk renovasi rumah, kantor kecil, dan ruang usaha.',
    address: 'Jl. Riau No. 45, Pekanbaru',
    city: 'Pekanbaru',
    province: 'Riau',
    postal_code: '28112',
    latitude: 0.5199,
    longitude: 101.4512,
    phone_number: '+62761234567',
    whatsapp_number: '+6281270001111',
    email: 'cs@riauinteriorstudio.id',
    website_url: 'https://riauinteriorstudio.id',
    google_maps_url: 'https://maps.google.com/?q=0.5199,101.4512',
    price_level: 'budget',
    average_price: 2500000,
    rating_average: 4.6,
    rating_count: 128,
    is_verified: true,
  },
  {
    id: 'aaaaaaaa-2222-4222-8222-aaaaaaaa2222',
    name: 'Nusantara Mebel & Dekor',
    categorySlug: 'toko-interior',
    short_description: 'Mebel, sofa, lemari, meja makan, dan dekorasi interior siap pakai.',
    full_description: 'Pilihan furniture rumah dan kantor dengan layanan antar. Tersedia perabot minimalis, dekorasi dinding, sofa, lemari, dan meja custom.',
    address: 'Jl. Tuanku Tambusai No. 88, Pekanbaru',
    city: 'Pekanbaru',
    province: 'Riau',
    postal_code: '28282',
    latitude: 0.5206,
    longitude: 101.439,
    phone_number: '+62761771088',
    whatsapp_number: '+6281270004444',
    email: 'halo@nusantaramebel.id',
    website_url: 'https://nusantaramebel.id',
    google_maps_url: 'https://maps.google.com/?q=0.5206,101.4390',
    price_level: 'midrange',
    average_price: 1800000,
    rating_average: 4.5,
    rating_count: 96,
    is_verified: true,
  },
  {
    id: 'aaaaaaaa-3333-4333-8333-aaaaaaaa3333',
    name: 'Dapur Indah Kitchen Set',
    categorySlug: 'toko-interior',
    short_description: 'Spesialis kitchen set, kabinet dapur, lemari, dan desain interior dapur.',
    full_description: 'Jasa ukur lokasi, desain 3D sederhana, produksi kitchen set, kabinet bawah tangga, dan lemari pakaian custom dengan pilihan material budget sampai premium.',
    address: 'Jl. Paus No. 31, Pekanbaru',
    city: 'Pekanbaru',
    province: 'Riau',
    postal_code: '28124',
    latitude: 0.4967,
    longitude: 101.4562,
    phone_number: '+62761818031',
    whatsapp_number: '+6281270005555',
    email: 'order@dapurindah.id',
    website_url: 'https://dapurindah.id',
    google_maps_url: 'https://maps.google.com/?q=0.4967,101.4562',
    price_level: 'premium',
    average_price: 6500000,
    rating_average: 4.7,
    rating_count: 74,
    is_verified: true,
  },
  {
    id: 'bbbbbbbb-1111-4111-8111-bbbbbbbb1111',
    name: 'Kopi Selasih Melayu',
    categorySlug: 'cafe-melayu',
    short_description: 'Cafe khas Melayu dengan kopi saring, teh tarik, roti jala, dan kue tradisional.',
    full_description: 'Menu unggulan: kopi saring, teh tarik, roti jala kari, bolu kemojo, lempeng kelapa, dan camilan khas Riau. Suasana cocok untuk keluarga dan kerja santai.',
    address: 'Jl. Sudirman No. 120, Pekanbaru',
    city: 'Pekanbaru',
    province: 'Riau',
    postal_code: '28116',
    latitude: 0.5095,
    longitude: 101.4549,
    phone_number: '+62761876543',
    whatsapp_number: '+6281270002222',
    email: 'hello@kopiselasih.co',
    website_url: 'https://kopiselasih.co',
    google_maps_url: 'https://maps.google.com/?q=0.5095,101.4549',
    price_level: 'midrange',
    average_price: 35000,
    rating_average: 4.4,
    rating_count: 342,
    is_verified: true,
  },
  {
    id: 'bbbbbbbb-2222-4222-8222-bbbbbbbb2222',
    name: 'Kedai Laksamana Riau',
    categorySlug: 'cafe-melayu',
    short_description: 'Kedai kopi dan kuliner Melayu: laksa, nasi lemak, teh tarik, dan kopi kampung.',
    full_description: 'Tempat makan santai dengan menu Melayu Riau, kopi kampung, teh tarik, laksa, nasi lemak, dan paket sarapan. Lokasi mudah dijangkau dari pusat kota.',
    address: 'Jl. Diponegoro No. 17, Pekanbaru',
    city: 'Pekanbaru',
    province: 'Riau',
    postal_code: '28131',
    latitude: 0.5142,
    longitude: 101.4485,
    phone_number: '+62761771717',
    whatsapp_number: '+6281270006666',
    email: 'kedai@laksamanariau.id',
    website_url: 'https://laksamanariau.id',
    google_maps_url: 'https://maps.google.com/?q=0.5142,101.4485',
    price_level: 'budget',
    average_price: 28000,
    rating_average: 4.6,
    rating_count: 188,
    is_verified: true,
  },
  {
    id: 'bbbbbbbb-3333-4333-8333-bbbbbbbb3333',
    name: 'Warung Roti Jala Mak Long',
    categorySlug: 'cafe-melayu',
    short_description: 'Warung makan Melayu rumahan dengan roti jala kari, kue tradisional, dan kopi saring.',
    full_description: 'Pilihan sarapan dan makan siang khas Melayu: roti jala, laksa, lempeng, kue talam, dan kopi saring. Area parkir motor tersedia.',
    address: 'Jl. Kuantan Raya No. 9, Pekanbaru',
    city: 'Pekanbaru',
    province: 'Riau',
    postal_code: '28143',
    latitude: 0.5023,
    longitude: 101.4617,
    phone_number: '+62761770009',
    whatsapp_number: '+6281270007777',
    email: 'maklong@rotijala.id',
    website_url: 'https://rotijala.id',
    google_maps_url: 'https://maps.google.com/?q=0.5023,101.4617',
    price_level: 'budget',
    average_price: 22000,
    rating_average: 4.3,
    rating_count: 139,
    is_verified: false,
  },
  {
    id: 'cccccccc-1111-4111-8111-cccccccc1111',
    name: 'Bengkel Mobil Mandiri Jaya',
    categorySlug: 'bengkel-mobil',
    short_description: 'Bengkel mobil umum dengan servis berkala, ganti oli, tune up, dan diagnosa cepat.',
    full_description: 'Layanan: servis berkala, ganti oli, tune up, kaki-kaki, rem, aki, dan diagnosa mesin. Estimasi biaya dijelaskan sebelum pengerjaan.',
    address: 'Jl. Arifin Ahmad No. 18, Pekanbaru',
    city: 'Pekanbaru',
    province: 'Riau',
    postal_code: '28125',
    latitude: 0.4989,
    longitude: 101.4231,
    phone_number: '+62761123456',
    whatsapp_number: '+6281270003333',
    email: 'service@mandirijaya-auto.id',
    website_url: 'https://mandirijaya-auto.id',
    google_maps_url: 'https://maps.google.com/?q=0.4989,101.4231',
    price_level: 'unknown',
    average_price: 400000,
    rating_average: 4.5,
    rating_count: 211,
    is_verified: true,
  },
  {
    id: 'cccccccc-2222-4222-8222-cccccccc2222',
    name: 'AutoCare Hangtuah',
    categorySlug: 'bengkel-mobil',
    short_description: 'Servis mobil, spooring balancing, ganti oli, aki, rem, dan ban.',
    full_description: 'Bengkel otomotif untuk perawatan mobil harian. Menangani ganti oli, tune up ringan, rem, aki, ban, spooring balancing, dan pengecekan mesin.',
    address: 'Jl. Hang Tuah No. 66, Pekanbaru',
    city: 'Pekanbaru',
    province: 'Riau',
    postal_code: '28155',
    latitude: 0.5262,
    longitude: 101.463,
    phone_number: '+62761770666',
    whatsapp_number: '+6281270008888',
    email: 'booking@autocarehangtuah.id',
    website_url: 'https://autocarehangtuah.id',
    google_maps_url: 'https://maps.google.com/?q=0.5262,101.4630',
    price_level: 'midrange',
    average_price: 350000,
    rating_average: 4.7,
    rating_count: 167,
    is_verified: true,
  },
  {
    id: 'cccccccc-3333-4333-8333-cccccccc3333',
    name: 'Bengkel Kaki-Kaki Tuah Karya',
    categorySlug: 'bengkel-mobil',
    short_description: 'Spesialis kaki-kaki mobil, shockbreaker, bushing, rem, dan pengecekan bunyi.',
    full_description: 'Bengkel mobil untuk keluhan kaki-kaki, stir getar, rem, shockbreaker, bearing, dan bunyi pada kolong mobil. Tersedia konsultasi awal.',
    address: 'Jl. Soekarno Hatta No. 210, Pekanbaru',
    city: 'Pekanbaru',
    province: 'Riau',
    postal_code: '28294',
    latitude: 0.4928,
    longitude: 101.4377,
    phone_number: '+62761770210',
    whatsapp_number: '+6281270009999',
    email: 'admin@tuahkarya-auto.id',
    website_url: 'https://tuahkarya-auto.id',
    google_maps_url: 'https://maps.google.com/?q=0.4928,101.4377',
    price_level: 'midrange',
    average_price: 450000,
    rating_average: 4.4,
    rating_count: 118,
    is_verified: false,
  },
    {
    id: 'ddddcccc-1111-4111-8111-ddddcccc1111',
    name: 'Sejuk Mandiri Service AC',
    categorySlug: 'jasa-ac-elektronik',
    short_description: 'Jasa AC terdekat untuk cuci AC, isi freon, bongkar pasang, dan servis AC rumah.',
    full_description: 'Teknisi AC panggilan untuk rumah, kos, toko, dan kantor kecil. Menangani cuci AC, isi freon, bocor halus, kapasitor, remote, dan perawatan berkala dengan jadwal booking.',
    address: 'Jl. Durian No. 52, Pekanbaru',
    city: 'Pekanbaru',
    province: 'Riau',
    postal_code: '28124',
    latitude: 0.5118,
    longitude: 101.4441,
    phone_number: '+62761770352',
    whatsapp_number: '+6281270010101',
    email: 'booking@sejukmandiri.id',
    website_url: 'https://sejukmandiri.id',
    google_maps_url: 'https://maps.google.com/?q=0.5118,101.4441',
    price_level: 'budget',
    average_price: 95000,
    rating_average: 4.8,
    rating_count: 204,
    is_verified: true,
  },
  {
    id: 'ddddcccc-2222-4222-8222-ddddcccc2222',
    name: 'AC Cepat Panam',
    categorySlug: 'jasa-ac-elektronik',
    short_description: 'Teknisi AC dan elektronik panggilan untuk servis cepat area kota dan kampus.',
    full_description: 'Layanan panggilan cuci AC, tambah freon, perbaikan AC tidak dingin, instalasi unit baru, dan cek elektronik rumah. Bisa booking jadwal pagi, siang, atau sore.',
    address: 'Jl. HR Soebrantas No. 144, Pekanbaru',
    city: 'Pekanbaru',
    province: 'Riau',
    postal_code: '28293',
    latitude: 0.4666,
    longitude: 101.3989,
    phone_number: '+62761770444',
    whatsapp_number: '+6281270010202',
    email: 'halo@accepatpanam.id',
    website_url: 'https://accepatpanam.id',
    google_maps_url: 'https://maps.google.com/?q=0.4666,101.3989',
    price_level: 'midrange',
    average_price: 125000,
    rating_average: 4.5,
    rating_count: 89,
    is_verified: true,
  },
  {
    id: 'eeeecccc-1111-4111-8111-eeeecccc1111',
    name: 'Herbal Sehat Riau',
    categorySlug: 'toko-herbal-kesehatan',
    short_description: 'Toko herbal terdekat dengan madu hutan, jamu tradisional, minyak herbal, dan edukasi sehat.',
    full_description: 'Menyediakan produk herbal lokal dan Nusantara seperti madu hutan, jamu kunyit asem, temulawak, minyak kayu putih, teh herbal, serta edukasi penggunaan produk secara bijak.',
    address: 'Jl. Hang Lekir No. 27, Pekanbaru',
    city: 'Pekanbaru',
    province: 'Riau',
    postal_code: '28131',
    latitude: 0.5079,
    longitude: 101.4527,
    phone_number: '+62761770527',
    whatsapp_number: '+6281270010303',
    email: 'info@herbalsehatriau.id',
    website_url: 'https://herbalsehatriau.id',
    google_maps_url: 'https://maps.google.com/?q=0.5079,101.4527',
    price_level: 'budget',
    average_price: 65000,
    rating_average: 4.7,
    rating_count: 156,
    is_verified: true,
  },
  {
    id: 'eeeecccc-2222-4222-8222-eeeecccc2222',
    name: 'Kedai Jamu Nusantara',
    categorySlug: 'toko-herbal-kesehatan',
    short_description: 'Jamu siap minum, racikan herbal, madu, dan minuman kesehatan lokal.',
    full_description: 'Kedai jamu dan produk herbal harian dengan menu kunyit asem, beras kencur, wedang jahe, madu, dan paket edukasi herbal untuk keluarga.',
    address: 'Jl. Pattimura No. 63, Pekanbaru',
    city: 'Pekanbaru',
    province: 'Riau',
    postal_code: '28132',
    latitude: 0.5156,
    longitude: 101.4595,
    phone_number: '+62761770663',
    whatsapp_number: '+6281270010404',
    email: 'kedai@jamunusantara.id',
    website_url: 'https://jamunusantara.id',
    google_maps_url: 'https://maps.google.com/?q=0.5156,101.4595',
    price_level: 'budget',
    average_price: 25000,
    rating_average: 4.4,
    rating_count: 97,
    is_verified: false,
  },
];

const offerings = [
  {
    id: 'dddddddd-1111-4111-8111-dddddddd1111',
    placeId: 'aaaaaaaa-1111-4111-8111-aaaaaaaa1111',
    name: 'Kitchen set minimalis custom',
    description: 'Produk custom untuk dapur rumah, termasuk ukur lokasi dan desain awal.',
    offering_type: 'product',
    price: 4500000,
    stock_status: 'by_request',
    stock_quantity: null,
    is_verified: true,
  },
  {
    id: 'dddddddd-1112-4112-8112-dddddddd1112',
    placeId: 'aaaaaaaa-1111-4111-8111-aaaaaaaa1111',
    name: 'Jasa desain interior ruang usaha',
    description: 'Konsultasi layout, warna, dan material untuk cafe, toko, atau kantor kecil.',
    offering_type: 'service',
    price: 750000,
    stock_status: 'by_request',
    stock_quantity: null,
    is_verified: true,
  },
  {
    id: 'dddddddd-1113-4113-8113-dddddddd1113',
    placeId: 'aaaaaaaa-1111-4111-8111-aaaaaaaa1111',
    name: 'Partisi ruangan kayu',
    description: 'Partisi dekoratif untuk rumah dan kantor.',
    offering_type: 'product',
    price: 1200000,
    stock_status: 'limited',
    stock_quantity: 4,
    is_verified: true,
  },
  {
    id: 'dddddddd-2221-4221-8221-dddddddd2221',
    placeId: 'aaaaaaaa-2222-4222-8222-aaaaaaaa2222',
    name: 'Sofa ruang tamu ready stock',
    description: 'Sofa minimalis dua dan tiga dudukan, tersedia pengiriman lokal.',
    offering_type: 'product',
    price: 2200000,
    stock_status: 'in_stock',
    stock_quantity: 7,
    is_verified: true,
  },
  {
    id: 'dddddddd-2222-4222-8222-dddddddd2222',
    placeId: 'aaaaaaaa-2222-4222-8222-aaaaaaaa2222',
    name: 'Lemari pakaian sliding',
    description: 'Lemari sliding siap pakai untuk kamar minimalis.',
    offering_type: 'product',
    price: 1850000,
    stock_status: 'limited',
    stock_quantity: 3,
    is_verified: true,
  },
  {
    id: 'dddddddd-2223-4223-8223-dddddddd2223',
    placeId: 'aaaaaaaa-2222-4222-8222-aaaaaaaa2222',
    name: 'Meja makan kayu jati',
    description: 'Meja makan keluarga dengan opsi kursi tambahan.',
    offering_type: 'product',
    price: 2800000,
    stock_status: 'in_stock',
    stock_quantity: 5,
    is_verified: true,
  },
  {
    id: 'dddddddd-3331-4331-8331-dddddddd3331',
    placeId: 'aaaaaaaa-3333-4333-8333-aaaaaaaa3333',
    name: 'Kabinet dapur bawah tangga',
    description: 'Kabinet custom untuk memaksimalkan ruang kecil.',
    offering_type: 'product',
    price: 5200000,
    stock_status: 'by_request',
    stock_quantity: null,
    is_verified: true,
  },
  {
    id: 'dddddddd-3332-4332-8332-dddddddd3332',
    placeId: 'aaaaaaaa-3333-4333-8333-aaaaaaaa3333',
    name: 'Jasa ukur dan desain 3D dapur',
    description: 'Survey lokasi, ukuran, dan gambar 3D sederhana sebelum produksi.',
    offering_type: 'service',
    price: 350000,
    stock_status: 'by_request',
    stock_quantity: null,
    is_verified: true,
  },
  {
    id: 'dddddddd-3333-4333-8333-dddddddd3333',
    placeId: 'aaaaaaaa-3333-4333-8333-aaaaaaaa3333',
    name: 'Top table granit kitchen set',
    description: 'Material top table untuk kitchen set premium.',
    offering_type: 'product',
    price: 1750000,
    stock_status: 'limited',
    stock_quantity: 2,
    is_verified: true,
  },
  {
    id: 'eeeeeeee-1111-4111-8111-eeeeeeee1111',
    placeId: 'bbbbbbbb-1111-4111-8111-bbbbbbbb1111',
    name: 'Kopi saring Melayu',
    description: 'Kopi saring panas khas Melayu, tersedia setiap hari.',
    offering_type: 'product',
    price: 18000,
    stock_status: 'in_stock',
    stock_quantity: 40,
    is_verified: true,
  },
  {
    id: 'eeeeeeee-1112-4112-8112-eeeeeeee1112',
    placeId: 'bbbbbbbb-1111-4111-8111-bbbbbbbb1111',
    name: 'Teh tarik rempah',
    description: 'Teh tarik hangat dengan aroma rempah ringan.',
    offering_type: 'product',
    price: 16000,
    stock_status: 'in_stock',
    stock_quantity: 35,
    is_verified: true,
  },
  {
    id: 'eeeeeeee-1113-4113-8113-eeeeeeee1113',
    placeId: 'bbbbbbbb-1111-4111-8111-bbbbbbbb1111',
    name: 'Roti jala kari ayam',
    description: 'Menu Melayu favorit untuk sarapan dan makan sore.',
    offering_type: 'product',
    price: 28000,
    stock_status: 'limited',
    stock_quantity: 9,
    is_verified: true,
  },
  {
    id: 'eeeeeeee-2221-4221-8221-eeeeeeee2221',
    placeId: 'bbbbbbbb-2222-4222-8222-bbbbbbbb2222',
    name: 'Laksa Melayu Riau',
    description: 'Laksa kuah gurih khas Melayu.',
    offering_type: 'product',
    price: 26000,
    stock_status: 'in_stock',
    stock_quantity: 28,
    is_verified: true,
  },
  {
    id: 'eeeeeeee-2222-4222-8222-eeeeeeee2222',
    placeId: 'bbbbbbbb-2222-4222-8222-bbbbbbbb2222',
    name: 'Nasi lemak ayam sambal',
    description: 'Paket nasi lemak dengan ayam dan sambal.',
    offering_type: 'product',
    price: 30000,
    stock_status: 'in_stock',
    stock_quantity: 22,
    is_verified: true,
  },
  {
    id: 'eeeeeeee-2223-4223-8223-eeeeeeee2223',
    placeId: 'bbbbbbbb-2222-4222-8222-bbbbbbbb2222',
    name: 'Paket booking sarapan kantor',
    description: 'Pesanan paket sarapan Melayu untuk tim kecil.',
    offering_type: 'service',
    price: 250000,
    stock_status: 'by_request',
    stock_quantity: null,
    is_verified: true,
  },
  {
    id: 'eeeeeeee-3331-4331-8331-eeeeeeee3331',
    placeId: 'bbbbbbbb-3333-4333-8333-bbbbbbbb3333',
    name: 'Roti jala kari daging',
    description: 'Roti jala rumahan dengan kari daging.',
    offering_type: 'product',
    price: 30000,
    stock_status: 'limited',
    stock_quantity: 6,
    is_verified: false,
  },
  {
    id: 'eeeeeeee-3332-4332-8332-eeeeeeee3332',
    placeId: 'bbbbbbbb-3333-4333-8333-bbbbbbbb3333',
    name: 'Kue talam Melayu',
    description: 'Kue tradisional untuk makan di tempat atau bungkus.',
    offering_type: 'product',
    price: 5000,
    stock_status: 'in_stock',
    stock_quantity: 45,
    is_verified: false,
  },
  {
    id: 'eeeeeeee-3333-4333-8333-eeeeeeee3333',
    placeId: 'bbbbbbbb-3333-4333-8333-bbbbbbbb3333',
    name: 'Kopi saring kampung',
    description: 'Kopi saring sederhana ala warung Melayu.',
    offering_type: 'product',
    price: 12000,
    stock_status: 'in_stock',
    stock_quantity: 30,
    is_verified: false,
  },
  {
    id: 'ffffffff-1111-4111-8111-ffffffff1111',
    placeId: 'cccccccc-1111-4111-8111-cccccccc1111',
    name: 'Ganti oli mobil 10W-40',
    description: 'Paket oli, filter, dan pengecekan ringan.',
    offering_type: 'service',
    price: 380000,
    stock_status: 'in_stock',
    stock_quantity: 18,
    is_verified: true,
  },
  {
    id: 'ffffffff-1112-4112-8112-ffffffff1112',
    placeId: 'cccccccc-1111-4111-8111-cccccccc1111',
    name: 'Servis berkala 10.000 km',
    description: 'Pemeriksaan mesin, oli, rem, aki, dan cairan kendaraan.',
    offering_type: 'service',
    price: 550000,
    stock_status: 'by_request',
    stock_quantity: null,
    is_verified: true,
  },
  {
    id: 'ffffffff-1113-4113-8113-ffffffff1113',
    placeId: 'cccccccc-1111-4111-8111-cccccccc1111',
    name: 'Aki mobil NS60',
    description: 'Aki mobil untuk kendaraan harian populer.',
    offering_type: 'product',
    price: 780000,
    stock_status: 'limited',
    stock_quantity: 5,
    is_verified: true,
  },
  {
    id: 'ffffffff-2221-4221-8221-ffffffff2221',
    placeId: 'cccccccc-2222-4222-8222-cccccccc2222',
    name: 'Spooring balancing',
    description: 'Layanan spooring dan balancing ban mobil.',
    offering_type: 'service',
    price: 250000,
    stock_status: 'by_request',
    stock_quantity: null,
    is_verified: true,
  },
  {
    id: 'ffffffff-2222-4222-8222-ffffffff2222',
    placeId: 'cccccccc-2222-4222-8222-cccccccc2222',
    name: 'Ban mobil ring 15',
    description: 'Ban ring 15 untuk city car dan MPV kecil.',
    offering_type: 'product',
    price: 720000,
    stock_status: 'limited',
    stock_quantity: 4,
    is_verified: true,
  },
  {
    id: 'ffffffff-2223-4223-8223-ffffffff2223',
    placeId: 'cccccccc-2222-4222-8222-cccccccc2222',
    name: 'Tune up ringan',
    description: 'Tune up ringan untuk performa mesin harian.',
    offering_type: 'service',
    price: 320000,
    stock_status: 'by_request',
    stock_quantity: null,
    is_verified: true,
  },
  {
    id: 'ffffffff-3331-4331-8331-ffffffff3331',
    placeId: 'cccccccc-3333-4333-8333-cccccccc3333',
    name: 'Perbaikan kaki-kaki mobil',
    description: 'Cek dan perbaikan bunyi kaki-kaki, bushing, dan bearing.',
    offering_type: 'service',
    price: 450000,
    stock_status: 'by_request',
    stock_quantity: null,
    is_verified: false,
  },
  {
    id: 'ffffffff-3332-4332-8332-ffffffff3332',
    placeId: 'cccccccc-3333-4333-8333-cccccccc3333',
    name: 'Shockbreaker depan',
    description: 'Komponen shockbreaker depan untuk beberapa model populer.',
    offering_type: 'product',
    price: 900000,
    stock_status: 'limited',
    stock_quantity: 2,
    is_verified: false,
  },
  {
    id: 'ffffffff-3333-4333-8333-ffffffff3333',
    placeId: 'cccccccc-3333-4333-8333-cccccccc3333',
    name: 'Cek rem dan bunyi kolong',
    description: 'Diagnosa awal rem, kaki-kaki, dan bunyi pada kolong mobil.',
    offering_type: 'service',
    price: 100000,
    stock_status: 'by_request',
    stock_quantity: null,
    is_verified: false,
  },
    {
    id: '99999999-1111-4111-8111-999999991111',
    placeId: 'ddddcccc-1111-4111-8111-ddddcccc1111',
    name: 'Cuci AC 1 PK',
    description: 'Jasa cuci AC rumah 0.5 sampai 1 PK dengan jadwal panggilan.',
    offering_type: 'service',
    price: 85000,
    stock_status: 'by_request',
    stock_quantity: null,
    is_verified: true,
  },
  {
    id: '99999999-1112-4112-8112-999999991112',
    placeId: 'ddddcccc-1111-4111-8111-ddddcccc1111',
    name: 'Isi freon AC R32',
    description: 'Tambah freon AC R32 setelah pengecekan tekanan dan kebocoran ringan.',
    offering_type: 'service',
    price: 180000,
    stock_status: 'by_request',
    stock_quantity: null,
    is_verified: true,
  },
  {
    id: '99999999-1113-4113-8113-999999991113',
    placeId: 'ddddcccc-1111-4111-8111-ddddcccc1111',
    name: 'Kapasitor AC 25uF',
    description: 'Sparepart kapasitor AC untuk beberapa model populer.',
    offering_type: 'product',
    price: 65000,
    stock_status: 'limited',
    stock_quantity: 6,
    is_verified: true,
  },
  {
    id: '99999999-2221-4221-8221-999999992221',
    placeId: 'ddddcccc-2222-4222-8222-ddddcccc2222',
    name: 'Bongkar pasang AC',
    description: 'Jasa bongkar pasang AC unit lama atau pindah lokasi.',
    offering_type: 'service',
    price: 350000,
    stock_status: 'by_request',
    stock_quantity: null,
    is_verified: true,
  },
  {
    id: '99999999-2222-4222-8222-999999992222',
    placeId: 'ddddcccc-2222-4222-8222-ddddcccc2222',
    name: 'Service AC tidak dingin',
    description: 'Diagnosa AC tidak dingin, cek freon, kipas, sensor, dan kebocoran ringan.',
    offering_type: 'service',
    price: 120000,
    stock_status: 'by_request',
    stock_quantity: null,
    is_verified: true,
  },
  {
    id: '88888888-1111-4111-8111-888888881111',
    placeId: 'eeeecccc-1111-4111-8111-eeeecccc1111',
    name: 'Madu hutan Riau 250 ml',
    description: 'Madu hutan lokal ukuran 250 ml, stok diperbarui harian.',
    offering_type: 'product',
    price: 75000,
    stock_status: 'in_stock',
    stock_quantity: 18,
    is_verified: true,
  },
  {
    id: '88888888-1112-4112-8112-888888881112',
    placeId: 'eeeecccc-1111-4111-8111-eeeecccc1111',
    name: 'Teh herbal serai jahe',
    description: 'Teh herbal siap seduh berbahan serai dan jahe.',
    offering_type: 'product',
    price: 42000,
    stock_status: 'in_stock',
    stock_quantity: 24,
    is_verified: true,
  },
  {
    id: '88888888-1113-4113-8113-888888881113',
    placeId: 'eeeecccc-1111-4111-8111-eeeecccc1111',
    name: 'Edukasi produk herbal keluarga',
    description: 'Sesi edukasi singkat untuk memilih produk herbal secara bijak.',
    offering_type: 'service',
    price: 50000,
    stock_status: 'by_request',
    stock_quantity: null,
    is_verified: true,
  },
  {
    id: '88888888-2221-4221-8221-888888882221',
    placeId: 'eeeecccc-2222-4222-8222-eeeecccc2222',
    name: 'Jamu kunyit asem botol',
    description: 'Jamu kunyit asem siap minum ukuran botol harian.',
    offering_type: 'product',
    price: 18000,
    stock_status: 'in_stock',
    stock_quantity: 30,
    is_verified: false,
  },
  {
    id: '88888888-2222-4222-8222-888888882222',
    placeId: 'eeeecccc-2222-4222-8222-eeeecccc2222',
    name: 'Wedang jahe merah',
    description: 'Minuman jahe merah hangat untuk kebutuhan harian.',
    offering_type: 'product',
    price: 15000,
    stock_status: 'limited',
    stock_quantity: 10,
    is_verified: false,
  },
];

const upsertCategory = async (queryInterface, category, transaction) => {
  await queryInterface.sequelize.query(
    `
      UPDATE place_categories
      SET
        name = :name,
        slug = :slug,
        description = :description,
        color_hex = :color_hex,
        icon_name = :icon_name,
        is_active = true,
        "updatedAt" = NOW()
      WHERE (slug = :slug OR LOWER(name) = LOWER(:name))
        AND "deletedAt" IS NULL;

      INSERT INTO place_categories (
        id, name, slug, description, color_hex, icon_name, is_active,
        "createdAt", "updatedAt", "deletedAt", "importHash"
      )
      SELECT
        :id, :name, :slug, :description, :color_hex, :icon_name, true,
        NOW(), NOW(), NULL, :importHash
      WHERE NOT EXISTS (
        SELECT 1 FROM place_categories
        WHERE (slug = :slug OR LOWER(name) = LOWER(:name))
          AND "deletedAt" IS NULL
      );
    `,
    {
      replacements: {
        ...category,
        importHash: `${CATEGORY_IMPORT_PREFIX}${category.slug}`,
      },
      transaction,
    },
  );
};

const findCategoryId = async (queryInterface, Sequelize, slug, transaction) => {
  const rows = await queryInterface.sequelize.query(
    `
      SELECT id FROM place_categories
      WHERE slug = :slug AND "deletedAt" IS NULL
      ORDER BY "createdAt" ASC
      LIMIT 1;
    `,
    {
      replacements: { slug },
      transaction,
      type: Sequelize.QueryTypes.SELECT,
    },
  );

  if (!rows.length) {
    throw new Error(`Kategori ${slug} tidak ditemukan saat memperbaiki data pencarian publik.`);
  }

  return rows[0].id;
};


const findPlaceId = async (queryInterface, Sequelize, name, transaction) => {
  const rows = await queryInterface.sequelize.query(
    `
      SELECT id FROM places
      WHERE LOWER(name) = LOWER(:name) AND "deletedAt" IS NULL
      ORDER BY "createdAt" ASC
      LIMIT 1;
    `,
    {
      replacements: { name },
      transaction,
      type: Sequelize.QueryTypes.SELECT,
    },
  );

  if (!rows.length) {
    throw new Error(`Tempat ${name} tidak ditemukan saat menautkan produk/jasa pencarian publik.`);
  }

  return rows[0].id;
};

const upsertPlace = async (queryInterface, place, categoryId, transaction) => {
  await queryInterface.sequelize.query(
    `
      UPDATE places
      SET
        "categoryId" = :categoryId,
        short_description = :short_description,
        full_description = :full_description,
        address = :address,
        city = :city,
        province = :province,
        postal_code = :postal_code,
        latitude = :latitude,
        longitude = :longitude,
        phone_number = :phone_number,
        whatsapp_number = :whatsapp_number,
        email = :email,
        website_url = :website_url,
        google_maps_url = :google_maps_url,
        price_level = :price_level,
        average_price = :average_price,
        rating_average = :rating_average,
        rating_count = :rating_count,
        status = 'published',
        is_verified = :is_verified,
        "updatedAt" = NOW()
      WHERE LOWER(name) = LOWER(:name)
        AND "deletedAt" IS NULL;

      INSERT INTO places (
        id, name, "categoryId", short_description, full_description, address, city, province,
        postal_code, latitude, longitude, phone_number, whatsapp_number, email, website_url,
        google_maps_url, price_level, average_price, rating_average, rating_count, status,
        is_verified, "createdAt", "updatedAt", "deletedAt", "importHash"
      )
      SELECT
        :id, :name, :categoryId, :short_description, :full_description, :address, :city, :province,
        :postal_code, :latitude, :longitude, :phone_number, :whatsapp_number, :email, :website_url,
        :google_maps_url, :price_level, :average_price, :rating_average, :rating_count, 'published',
        :is_verified, NOW(), NOW(), NULL, :importHash
      WHERE NOT EXISTS (
        SELECT 1 FROM places
        WHERE LOWER(name) = LOWER(:name)
          AND "deletedAt" IS NULL
      );
    `,
    {
      replacements: {
        ...place,
        categoryId,
        importHash: `${PLACE_IMPORT_PREFIX}${place.id}`,
      },
      transaction,
    },
  );
};


const upsertOffering = async (queryInterface, offering, transaction) => {
  await queryInterface.sequelize.query(
    `
      UPDATE place_offerings
      SET
        "placeId" = :placeId,
        name = :name,
        description = :description,
        offering_type = :offering_type,
        price = :price,
        stock_status = :stock_status,
        stock_quantity = :stock_quantity,
        is_verified = :is_verified,
        is_active = true,
        last_stock_update = COALESCE(:last_stock_update, NOW()),
        "updatedAt" = NOW()
      WHERE "importHash" = :importHash
        AND "deletedAt" IS NULL;

      INSERT INTO place_offerings (
        id, "placeId", name, description, offering_type, price, stock_status,
        stock_quantity, is_verified, is_active, last_stock_update,
        "createdAt", "updatedAt", "deletedAt", "importHash"
      )
      SELECT
        :id, :placeId, :name, :description, :offering_type, :price, :stock_status,
        :stock_quantity, :is_verified, true, COALESCE(:last_stock_update, NOW()),
        NOW(), NOW(), NULL, :importHash
      WHERE NOT EXISTS (
        SELECT 1 FROM place_offerings
        WHERE "importHash" = :importHash
          AND "deletedAt" IS NULL
      );
    `,
    {
      replacements: {
        ...offering,
        last_stock_update: offering.last_stock_update || null,
        importHash: `${OFFERING_IMPORT_PREFIX}${offering.id}`,
      },
      transaction,
    },
  );
};

module.exports = {
  up: async (queryInterface, Sequelize) => {
    const transaction = await queryInterface.sequelize.transaction();

    try {
      for (const category of categories) {
        await upsertCategory(queryInterface, category, transaction);
      }

      const actualPlaceIds = {};
      for (const place of places) {
        const categoryId = await findCategoryId(queryInterface, Sequelize, place.categorySlug, transaction);
        await upsertPlace(queryInterface, place, categoryId, transaction);
        actualPlaceIds[place.id] = await findPlaceId(queryInterface, Sequelize, place.name, transaction);
      }

      for (const offering of offerings) {
        await upsertOffering(queryInterface, {
          ...offering,
          placeId: actualPlaceIds[offering.placeId] || offering.placeId,
        }, transaction);
      }

      await transaction.commit();
    } catch (err) {
      await transaction.rollback();
      throw err;
    }
  },

  down: async (queryInterface) => {
    const transaction = await queryInterface.sequelize.transaction();

    try {
      await queryInterface.sequelize.query(
        'DELETE FROM place_offerings WHERE "importHash" LIKE :prefix;',
        {
          replacements: { prefix: `${OFFERING_IMPORT_PREFIX}%` },
          transaction,
        },
      );

      await queryInterface.sequelize.query(
        'DELETE FROM places WHERE "importHash" LIKE :prefix;',
        {
          replacements: { prefix: `${PLACE_IMPORT_PREFIX}%` },
          transaction,
        },
      );

      await queryInterface.sequelize.query(
        'DELETE FROM place_categories WHERE "importHash" LIKE :prefix;',
        {
          replacements: { prefix: `${CATEGORY_IMPORT_PREFIX}%` },
          transaction,
        },
      );

      await transaction.commit();
    } catch (err) {
      await transaction.rollback();
      throw err;
    }
  },
};
