#!/usr/bin/env node

/**
 * Sync ALL Prisma data to Supabase
 * This script copies all existing data from Prisma PostgreSQL to Supabase
 */

import { PrismaClient } from '../lib/generated/prisma/index.js';
import { createClient } from '@supabase/supabase-js';
import dotenv from 'dotenv';

dotenv.config({ path: '.env.local' });

const prisma = new PrismaClient();
const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL,
  process.env.SUPABASE_SERVICE_ROLE_KEY
);

async function syncTable(tableName, prismaModel, mapData = (row) => row) {
  console.log(`\n📊 Syncing ${tableName}...`);

  try {
    // Get all data from Prisma
    const prismaData = await prismaModel.findMany();
    console.log(`   Found ${prismaData.length} rows in Prisma`);

    if (prismaData.length === 0) {
      console.log(`   ℹ️  No data to sync`);
      return { synced: 0, skipped: 0, errors: 0 };
    }

    // Map and insert data to Supabase
    let synced = 0;
    let skipped = 0;
    let errors = 0;

    for (const row of prismaData) {
      try {
        const mappedData = mapData(row);

        // Use upsert to handle existing data
        const { error } = await supabase
          .from(tableName)
          .upsert(mappedData, { onConflict: 'id' });

        if (error) {
          console.error(`   ❌ Error syncing row ${row.id}:`, error.message);
          errors++;
        } else {
          synced++;
        }
      } catch (err) {
        console.error(`   ❌ Exception syncing row ${row.id}:`, err.message);
        errors++;
      }
    }

    console.log(`   ✅ Synced: ${synced} | Skipped: ${skipped} | Errors: ${errors}`);
    return { synced, skipped, errors };
  } catch (error) {
    console.error(`   ❌ Failed to sync ${tableName}:`, error.message);
    return { synced: 0, skipped: 0, errors: 1 };
  }
}

async function main() {
  console.log('🚀 Starting Prisma → Supabase Data Sync');
  console.log('==========================================\n');

  const results = {};

  // 1. Users
  results.users = await syncTable('users', prisma.users, (user) => ({
    id: user.id,
    email: user.email,
    name: user.name,
    password: user.password,
    username: user.username,
    role: user.role,
    google_id: user.googleId,
    email_verified: user.emailVerified,
    created_at: user.createdAt,
    updated_at: user.updatedAt,
    last_login_at: user.lastLoginAt,
    last_login_ip: user.lastLoginIp,
    failed_attempts: user.failedAttempts,
    locked_until: user.lockedUntil,
    is_active: user.isActive,
    address: user.address,
    company_name: user.companyName,
    company_size: user.companySize,
    industry: user.industry,
    onboarding_complete: user.onboardingComplete,
    phone_number: user.phoneNumber,
    website: user.website,
    country: user.country,
    city: user.city,
    selected_package: user.selectedPackage,
    goals: user.goals,
    stripe_customer_id: user.stripeCustomerId,
    n8n_webhook_url: user.n8nWebhookUrl,
    n8n_workflow_id: user.n8nWorkflowId,
    whatsapp_connected: user.whatsappConnected,
    whatsapp_number: user.whatsappNumber,
    whatsapp_connected_at: user.whatsappConnectedAt,
    is_suspended: user.isSuspended,
    suspended_at: user.suspendedAt,
    suspended_by: user.suspendedBy,
    suspended_reason: user.suspendedReason,
    last_login_country: user.lastLoginCountry,
    last_login_city: user.lastLoginCity,
    login_count: user.loginCount,
  }));

  // 2. Audit Logs
  results.audit_logs = await syncTable('audit_logs', prisma.audit_logs, (log) => ({
    id: log.id,
    user_id: log.userId,
    type: log.type,
    action: log.action,
    success: log.success,
    ip: log.ip,
    user_agent: log.userAgent,
    metadata: log.metadata,
    created_at: log.createdAt,
  }));

  // 3. Subscriptions
  results.subscriptions = await syncTable('subscriptions', prisma.subscriptions, (sub) => ({
    id: sub.id,
    user_id: sub.userId,
    stripe_customer_id: sub.stripeCustomerId,
    stripe_subscription_id: sub.stripeSubscriptionId,
    stripe_price_id: sub.stripePriceId,
    tier_id: sub.tierId,
    status: sub.status,
    billing_period: sub.billingPeriod,
    current_period_end: sub.currentPeriodEnd,
    trial_ends_at: sub.trialEndsAt,
    cancel_at_period_end: sub.cancelAtPeriodEnd,
    cancelled_at: sub.cancelledAt,
    last_payment_date: sub.lastPaymentDate,
    last_payment_attempt: sub.lastPaymentAttempt,
    payment_failure_count: sub.paymentFailureCount,
    payment_method_id: sub.paymentMethodId,
    card_brand: sub.cardBrand,
    card_last_four: sub.cardLastFour,
    setup_fee_paid: sub.setupFeePaid,
    setup_fee_paid_at: sub.setupFeePaidAt,
    setup_fee_amount: sub.setupFeeAmount,
    created_at: sub.createdAt,
    updated_at: sub.updatedAt,
  }));

  // 4. Billing History
  results.billing_history = await syncTable('billing_history', prisma.billing_history, (bill) => ({
    id: bill.id,
    customer_id: bill.customerId,
    subscription_id: bill.subscriptionId,
    invoice_id: bill.invoiceId,
    payment_intent_id: bill.paymentIntentId,
    event: bill.event,
    amount: bill.amount,
    currency: bill.currency,
    metadata: bill.metadata,
    created_at: bill.createdAt,
  }));

  // 5. Payments
  results.payments = await syncTable('payments', prisma.payments, (payment) => ({
    id: payment.id,
    stripe_payment_intent_id: payment.stripePaymentIntentId,
    stripe_session_id: payment.stripeSessionId,
    amount: payment.amount,
    currency: payment.currency,
    status: payment.status,
    customer_id: payment.customerId,
    customer_email: payment.customerEmail,
    succeeded_at: payment.succeededAt,
    failed_at: payment.failedAt,
    error_message: payment.errorMessage,
    metadata: payment.metadata,
    created_at: payment.createdAt,
    updated_at: payment.updatedAt,
  }));

  // 6. Demo Bookings
  results.demo_bookings = await syncTable('demo_bookings', prisma.demo_bookings, (demo) => ({
    id: demo.id,
    full_name: demo.fullName,
    email: demo.email,
    telephone: demo.telephone,
    appointment_date: demo.appointmentDate,
    appointment_time: demo.appointmentTime,
    duration: demo.duration,
    special_requirements: demo.specialRequirements,
    language: demo.language,
    status: demo.status,
    webhook_status: demo.webhookStatus,
    webhook_retry_count: demo.webhookRetryCount,
    webhook_last_attempt: demo.webhookLastAttempt,
    webhook_response: demo.webhookResponse,
    assigned_to: demo.assignedTo,
    contacted_at: demo.contactedAt,
    contacted_by: demo.contactedBy,
    meeting_link: demo.meetingLink,
    internal_notes: demo.internalNotes,
    created_at: demo.createdAt,
    updated_at: demo.updatedAt,
  }));

  // 7. OTPs
  results.otps = await syncTable('otps', prisma.otps, (otp) => ({
    id: otp.id,
    email: otp.email,
    otp_code: otp.otpCode,
    purpose: otp.purpose,
    expires_at: otp.expiresAt,
    verified: otp.verified,
    verified_at: otp.verifiedAt,
    ip_address: otp.ipAddress,
    created_at: otp.createdAt,
    updated_at: otp.updatedAt,
  }));

  // 8. Contacts (map to contacts table, not contact_submissions)
  results.contacts = await syncTable('contacts', prisma.contacts, (contact) => ({
    id: contact.id,
    name: contact.name,
    email: contact.email,
    phone: contact.phone,
    company: contact.company,
    message: contact.message,
    language: contact.language,
    status: contact.status,
    assigned_to: contact.assignedTo,
    responded_by: contact.respondedBy,
    responded_at: contact.respondedAt,
    internal_notes: contact.internalNotes,
    created_at: contact.createdAt,
    updated_at: contact.updatedAt,
  }));

  // 9. Staff Alerts
  results.staff_alerts = await syncTable('staff_alerts', prisma.staff_alerts, (alert) => ({
    id: alert.id,
    type: alert.type,
    title: alert.title,
    message: alert.message,
    severity: alert.severity,
    is_read: alert.isRead,
    read_at: alert.readAt,
    read_by: alert.readBy,
    metadata: alert.metadata,
    created_at: alert.createdAt,
  }));

  // 10. Login History
  results.login_history = await syncTable('login_history', prisma.login_history, (login) => ({
    id: login.id,
    user_id: login.userId,
    ip_address: login.ipAddress,
    user_agent: login.userAgent,
    country: login.country,
    country_code: login.countryCode,
    city: login.city,
    region: login.region,
    latitude: login.latitude,
    longitude: login.longitude,
    timezone: login.timezone,
    provider: login.provider,
    success: login.success,
    fail_reason: login.failReason,
    created_at: login.createdAt,
  }));

  // 11. Careers landing page
  results.careers = await syncTable('careers', prisma.careers, (career) => ({
    id: career.id,
    slug: career.slug,
    title_translations: career.titleTranslations,
    hero_lead_translations: career.heroLeadTranslations,
    hero_description_translations: career.heroDescriptionTranslations,
    about_company: career.aboutCompany,
    how_we_work: career.howWeWork,
    how_to_apply: career.howToApply,
    created_at: career.createdAt,
    updated_at: career.updatedAt,
  }));

  // 12. Jobs
  results.jobs = await syncTable('jobs', prisma.jobs, (job) => ({
    id: job.id,
    career_id: job.careerId,
    slug: job.slug,
    title_translations: job.titleTranslations,
    department: job.department,
    department_label: job.departmentLabel,
    location_translations: job.locationTranslations,
    contract_type: job.contractType,
    contract_type_label: job.contractTypeLabel,
    level: job.level,
    level_label: job.levelLabel,
    compensation_translations: job.compensationTranslations,
    benefits: job.benefits,
    skills: job.skills,
    requirements: job.requirements,
    responsibilities: job.responsibilities,
    nice_to_have: job.niceToHave,
    workday_expectations: job.workdayExpectations,
    application_instructions: job.applicationInstructions,
    status: job.status,
    opening_at: job.openingAt,
    closing_at: job.closingAt,
    created_at: job.createdAt,
    updated_at: job.updatedAt,
  }));

  // 13. Job Applications
  results.job_applications = await syncTable('job_applications', prisma.job_applications, (app) => ({
    id: app.id,
    job_id: app.jobId,
    applicant_name: app.applicantName,
    applicant_email: app.applicantEmail,
    applicant_phone: app.applicantPhone,
    applicant_linkedin: app.applicantLinkedin,
    applicant_portfolio: app.applicantPortfolio,
    cover_note: app.coverNote,
    cv_bucket: app.cvBucket,
    cv_path: app.cvPath,
    cv_filename: app.cvFilename,
    cv_bytes: app.cvBytes,
    cv_mime_type: app.cvMimeType,
    submission_language: app.submissionLanguage,
    submitted_at: app.submittedAt,
    metadata: app.metadata,
    created_at: app.createdAt,
  }));

  // 14-22. Other tables (may be empty, check if data exists)
  const otherTables = [
    { name: 'whatsapp_conversations', model: prisma.whatsAppConversation },
    { name: 'conversation_messages', model: prisma.conversationMessage },
    { name: 'integrations', model: prisma.integration },
    { name: 'bookings', model: prisma.booking },
    { name: 'notifications', model: prisma.notification },
    { name: 'staff_notes', model: prisma.staffNote },
    { name: 'site_visits', model: prisma.siteVisit },
    { name: 'admin_notes', model: prisma.adminNote },
    { name: 'billing_emails', model: prisma.billingEmail },
  ];

  for (const { name, model } of otherTables) {
    try {
      const data = await model.findMany();
      console.log(`\n📊 ${name}: ${data.length} rows`);
      if (data.length > 0) {
        // These might have data - would need custom mapping
        console.log(`   ℹ️  Has data but needs custom field mapping`);
      }
    } catch (error) {
      console.log(`   ℹ️  ${name}: No data or model not accessible`);
    }
  }

  // ======================================
  // 105. REVIEWS
  // ======================================
  results.reviews = await syncTable('reviews', prisma.reviews, (row) => ({
    id: row.id,
    userId: row.userId,
    customerName: row.customerName,
    customerEmail: row.customerEmail,
    customerPhone: row.customerPhone,
    platform: row.platform,
    rating: row.rating,
    title: row.title,
    content: row.content,
    language: row.language,
    isVerified: row.isVerified,
    responseText: row.responseText,
    respondedAt: toIso(row.respondedAt),
    reviewRequestId: row.reviewRequestId,
    createdAt: toIso(row.createdAt),
    updatedAt: toIso(row.updatedAt),
  }));

  // ======================================
  // 106. REVIEW REQUESTS
  // ======================================
  results.review_requests = await syncTable('review_requests', prisma.review_requests, (row) => ({
    id: row.id,
    userId: row.userId,
    customerName: row.customerName,
    customerEmail: row.customerEmail,
    customerPhone: row.customerPhone,
    channel: row.channel,
    token: row.token,
    message: row.message,
    language: row.language,
    status: row.status,
    sentAt: toIso(row.sentAt),
    completedAt: toIso(row.completedAt),
    expiresAt: toIso(row.expiresAt),
    createdAt: toIso(row.createdAt),
    updatedAt: toIso(row.updatedAt),
  }));

  // ======================================
  // 107. REFERRALS
  // ======================================
  results.referrals = await syncTable('referrals', prisma.referrals, (row) => ({
    id: row.id,
    userId: row.userId,
    code: row.code,
    name: row.name,
    description: row.description,
    rewardType: row.rewardType,
    rewardValue: row.rewardValue,
    rewardCurrency: row.rewardCurrency,
    maxUses: row.maxUses,
    expiresAt: toIso(row.expiresAt),
    uses: row.uses,
    conversions: row.conversions,
    rewardsIssued: row.rewardsIssued,
    lastConvertedAt: toIso(row.lastConvertedAt),
    lastRewardAt: toIso(row.lastRewardAt),
    status: row.status,
    createdAt: toIso(row.createdAt),
    updatedAt: toIso(row.updatedAt),
  }));

  // ======================================
  // 108. QUOTATIONS
  // ======================================
  results.quotations = await syncTable('quotations', prisma.quotations, (row) => ({
    id: row.id,
    userId: row.userId,
    customerId: row.customerId,
    quotationNumber: row.quotationNumber,
    title: row.title,
    notes: row.notes,
    status: row.status,
    currency: row.currency,
    subtotal: row.subtotal,
    taxRate: row.taxRate,
    taxAmount: row.taxAmount,
    discountRate: row.discountRate,
    discountAmount: row.discountAmount,
    total: row.total,
    validUntil: toIso(row.validUntil),
    sentAt: toIso(row.sentAt),
    viewedAt: toIso(row.viewedAt),
    respondedAt: toIso(row.respondedAt),
    metadata: row.metadata,
    createdAt: toIso(row.createdAt),
    updatedAt: toIso(row.updatedAt),
  }));

  // ======================================
  // 109. QUOTATION ITEMS
  // ======================================
  results.quotation_items = await syncTable('quotation_items', prisma.quotation_items, (row) => ({
    id: row.id,
    quotationId: row.quotationId,
    description: row.description,
    quantity: row.quantity,
    unitPrice: row.unitPrice,
    total: row.total,
    sortOrder: row.sortOrder,
    createdAt: toIso(row.createdAt),
    updatedAt: toIso(row.updatedAt),
  }));

  // ======================================
  // 110. DEALS
  // ======================================
  results.deals = await syncTable('deals', prisma.deals, (row) => ({
    id: row.id,
    userId: row.userId,
    customerId: row.customerId,
    quotationId: row.quotationId,
    title: row.title,
    value: row.value,
    currency: row.currency,
    stage: row.stage,
    probability: row.probability,
    expectedCloseDate: toIso(row.expectedCloseDate),
    closedAt: toIso(row.closedAt),
    lostReason: row.lostReason,
    notes: row.notes,
    metadata: row.metadata,
    createdAt: toIso(row.createdAt),
    updatedAt: toIso(row.updatedAt),
  }));

  // ======================================
  // 111. EXPENSE CATEGORIES
  // ======================================
  results.expense_categories = await syncTable('expense_categories', prisma.expense_categories, (row) => ({
    id: row.id,
    userId: row.userId,
    name: row.name,
    nameAr: row.nameAr,
    color: row.color,
    icon: row.icon,
    sortOrder: row.sortOrder,
    createdAt: toIso(row.createdAt),
    updatedAt: toIso(row.updatedAt),
  }));

  // ======================================
  // 112. EXPENSES
  // ======================================
  results.expenses = await syncTable('expenses', prisma.expenses, (row) => ({
    id: row.id,
    userId: row.userId,
    categoryId: row.categoryId,
    amount: row.amount,
    currency: row.currency,
    vendor: row.vendor,
    description: row.description,
    date: toIso(row.date),
    receiptUrl: row.receiptUrl,
    isRecurring: row.isRecurring,
    recurringFrequency: row.recurringFrequency,
    tags: row.tags,
    notes: row.notes,
    createdAt: toIso(row.createdAt),
    updatedAt: toIso(row.updatedAt),
  }));

  // ======================================
  // 113. BROKERS
  // ======================================
  results.Broker = await syncTable('Broker', prisma.broker, (row) => ({
    id: row.id,
    userId: row.userId,
    organizationId: row.organizationId,
    nameEn: row.nameEn,
    nameAr: row.nameAr,
    phone: row.phone,
    email: row.email,
    whatsappNumber: row.whatsappNumber,
    photoUrl: row.photoUrl,
    bioEn: row.bioEn,
    bioAr: row.bioAr,
    licenseNumber: row.licenseNumber,
    languages: row.languages,
    areaSpecializations: row.areaSpecializations,
    typeSpecializations: row.typeSpecializations,
    workingDays: row.workingDays,
    workStartTime: row.workStartTime,
    workEndTime: row.workEndTime,
    maxViewingsPerDay: row.maxViewingsPerDay,
    isActive: row.isActive,
    totalViewings: row.totalViewings,
    totalClosings: row.totalClosings,
    createdAt: toIso(row.createdAt),
    updatedAt: toIso(row.updatedAt),
  }));

  // ======================================
  // 114. BROKER AVAILABILITY
  // ======================================
  results.BrokerAvailability = await syncTable('BrokerAvailability', prisma.brokerAvailability, (row) => ({
    id: row.id,
    brokerId: row.brokerId,
    date: toIso(row.date),
    startTime: row.startTime,
    endTime: row.endTime,
    isBlocked: row.isBlocked,
    reason: row.reason,
    createdAt: toIso(row.createdAt),
  }));

  // ======================================
  // 115. PROPERTIES
  // ======================================
  results.Property = await syncTable('Property', prisma.property, (row) => ({
    id: row.id,
    userId: row.userId,
    organizationId: row.organizationId,
    titleEn: row.titleEn,
    titleAr: row.titleAr,
    descriptionEn: row.descriptionEn,
    descriptionAr: row.descriptionAr,
    referenceNumber: row.referenceNumber,
    propertyType: row.propertyType,
    listingType: row.listingType,
    status: row.status,
    furnishing: row.furnishing,
    ownership: row.ownership,
    isOffPlan: row.isOffPlan,
    handoverDate: toIso(row.handoverDate),
    bedrooms: row.bedrooms,
    bathrooms: row.bathrooms,
    builtUpArea: row.builtUpArea,
    plotArea: row.plotArea,
    floor: row.floor,
    totalFloors: row.totalFloors,
    parkingSpaces: row.parkingSpaces,
    yearBuilt: row.yearBuilt,
    country: row.country,
    city: row.city,
    district: row.district,
    buildingName: row.buildingName,
    unitNumber: row.unitNumber,
    latitude: toDecimal(row.latitude),
    longitude: toDecimal(row.longitude),
    mapUrl: row.mapUrl,
    price: row.price,
    currency: row.currency,
    pricePerSqm: row.pricePerSqm,
    isNegotiable: row.isNegotiable,
    serviceCharges: row.serviceCharges,
    minContractMonths: row.minContractMonths,
    paymentTerms: row.paymentTerms,
    amenities: row.amenities,
    highlights: row.highlights,
    keyLocation: row.keyLocation,
    accessNotes: row.accessNotes,
    viewingHoursNote: row.viewingHoursNote,
    listingBrokerId: row.listingBrokerId,
    viewCount: row.viewCount,
    inquiryCount: row.inquiryCount,
    viewingCount: row.viewingCount,
    listedAt: toIso(row.listedAt),
    soldRentedAt: toIso(row.soldRentedAt),
    createdAt: toIso(row.createdAt),
    updatedAt: toIso(row.updatedAt),
  }));

  // ======================================
  // 116. PROPERTY IMAGES
  // ======================================
  results.PropertyImage = await syncTable('PropertyImage', prisma.propertyImage, (row) => ({
    id: row.id,
    propertyId: row.propertyId,
    url: row.url,
    caption: row.caption,
    captionAr: row.captionAr,
    type: row.type,
    sortOrder: row.sortOrder,
    isPrimary: row.isPrimary,
    createdAt: toIso(row.createdAt),
  }));

  // ======================================
  // 117. VIEWING TOURS
  // ======================================
  results.ViewingTour = await syncTable('ViewingTour', prisma.viewingTour, (row) => ({
    id: row.id,
    userId: row.userId,
    organizationId: row.organizationId,
    brokerId: row.brokerId,
    clientName: row.clientName,
    clientPhone: row.clientPhone,
    tourDate: toIso(row.tourDate),
    startTime: row.startTime,
    estimatedEnd: row.estimatedEnd,
    notes: row.notes,
    status: row.status,
    createdAt: toIso(row.createdAt),
    updatedAt: toIso(row.updatedAt),
  }));

  // ======================================
  // 118. PROPERTY VIEWINGS
  // ======================================
  results.PropertyViewing = await syncTable('PropertyViewing', prisma.propertyViewing, (row) => ({
    id: row.id,
    userId: row.userId,
    organizationId: row.organizationId,
    propertyId: row.propertyId,
    brokerId: row.brokerId,
    tourId: row.tourId,
    clientName: row.clientName,
    clientPhone: row.clientPhone,
    clientEmail: row.clientEmail,
    viewingType: row.viewingType,
    viewingDate: toIso(row.viewingDate),
    viewingTime: row.viewingTime,
    duration: row.duration,
    status: row.status,
    meetingLink: row.meetingLink,
    clientTimezone: row.clientTimezone,
    maxAttendees: row.maxAttendees,
    currentAttendees: row.currentAttendees,
    accessConfirmed: row.accessConfirmed,
    keyCollected: row.keyCollected,
    interestLevel: row.interestLevel,
    clientNotes: row.clientNotes,
    confirmationSentAt: toIso(row.confirmationSentAt),
    reminder24hSentAt: toIso(row.reminder24hSentAt),
    reminder2hSentAt: toIso(row.reminder2hSentAt),
    followUpSentAt: toIso(row.followUpSentAt),
    source: row.source,
    conversationId: row.conversationId,
    createdAt: toIso(row.createdAt),
    updatedAt: toIso(row.updatedAt),
  }));

  // ======================================
  // 119. VIEWING FEEDBACK
  // ======================================
  results.ViewingFeedback = await syncTable('ViewingFeedback', prisma.viewingFeedback, (row) => ({
    id: row.id,
    viewingId: row.viewingId,
    overallRating: row.overallRating,
    priceOpinion: row.priceOpinion,
    sizeOpinion: row.sizeOpinion,
    locationOpinion: row.locationOpinion,
    conditionNote: row.conditionNote,
    wouldRecommend: row.wouldRecommend,
    brokerNotes: row.brokerNotes,
    interestLevel: row.interestLevel,
    suggestedAction: row.suggestedAction,
    createdAt: toIso(row.createdAt),
  }));

  // ======================================
  // 120. CLIENT REQUIREMENTS
  // ======================================
  results.ClientRequirements = await syncTable('ClientRequirements', prisma.clientRequirements, (row) => ({
    id: row.id,
    userId: row.userId,
    organizationId: row.organizationId,
    customerId: row.customerId,
    clientName: row.clientName,
    clientPhone: row.clientPhone,
    clientEmail: row.clientEmail,
    listingType: row.listingType,
    propertyTypes: row.propertyTypes,
    minBedrooms: row.minBedrooms,
    maxBedrooms: row.maxBedrooms,
    minBudget: row.minBudget,
    maxBudget: row.maxBudget,
    currency: row.currency,
    preferredAreas: row.preferredAreas,
    minArea: row.minArea,
    mustHaves: row.mustHaves,
    dealBreakers: row.dealBreakers,
    timeline: row.timeline,
    purpose: row.purpose,
    financingType: row.financingType,
    preApproved: row.preApproved,
    leadScore: row.leadScore,
    lastContactAt: toIso(row.lastContactAt),
    isActive: row.isActive,
    createdAt: toIso(row.createdAt),
    updatedAt: toIso(row.updatedAt),
  }));

  // ======================================
  // 121. PROPERTY MATCHES
  // ======================================
  results.PropertyMatch = await syncTable('PropertyMatch', prisma.propertyMatch, (row) => ({
    id: row.id,
    propertyId: row.propertyId,
    requirementId: row.requirementId,
    matchScore: row.matchScore,
    matchReasons: row.matchReasons,
    status: row.status,
    sentAt: toIso(row.sentAt),
    createdAt: toIso(row.createdAt),
  }));

  // ======================================
  // 122. REAL ESTATE TRANSACTIONS
  // ======================================
  results.RealEstateTransaction = await syncTable('RealEstateTransaction', prisma.realEstateTransaction, (row) => ({
    id: row.id,
    userId: row.userId,
    organizationId: row.organizationId,
    propertyId: row.propertyId,
    clientName: row.clientName,
    clientPhone: row.clientPhone,
    clientEmail: row.clientEmail,
    brokerId: row.brokerId,
    stage: row.stage,
    offerAmount: row.offerAmount,
    counterAmount: row.counterAmount,
    agreedAmount: row.agreedAmount,
    currency: row.currency,
    depositAmount: row.depositAmount,
    depositPaid: row.depositPaid,
    depositPaidAt: toIso(row.depositPaidAt),
    depositPaymentId: row.depositPaymentId,
    offerDate: toIso(row.offerDate),
    contractDate: toIso(row.contractDate),
    completionDate: toIso(row.completionDate),
    handoverDate: toIso(row.handoverDate),
    notes: row.notes,
    lostReason: row.lostReason,
    createdAt: toIso(row.createdAt),
    updatedAt: toIso(row.updatedAt),
  }));

  // Print summary
  console.log('\n==========================================');
  console.log('📈 SYNC SUMMARY');
  console.log('==========================================\n');

  let totalSynced = 0;
  let totalErrors = 0;

  Object.entries(results).forEach(([table, stats]) => {
    if (stats) {
      console.log(`${table}:`);
      console.log(`  ✅ Synced: ${stats.synced}`);
      if (stats.errors > 0) {
        console.log(`  ❌ Errors: ${stats.errors}`);
      }
      totalSynced += stats.synced;
      totalErrors += stats.errors;
    }
  });

  console.log(`\n==========================================`);
  console.log(`Total Synced: ${totalSynced} rows`);
  console.log(`Total Errors: ${totalErrors}`);
  console.log(`==========================================\n`);

  if (totalErrors === 0) {
    console.log('✨ All data synced successfully!');
  } else {
    console.log('⚠️  Some errors occurred. Check logs above.');
  }
}

main()
  .catch((error) => {
    console.error('❌ Fatal error:', error);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
