import { Injectable, NotFoundException, BadRequestException, Logger } from '@nestjs/common';
import { PrismaService } from '../../../prisma/prisma.service';
import { ConnectorFactory } from '../../connectors/connector.factory';
import { PaymentFactory } from '../../payments/payment.factory';
import { PaymentPollingService } from '../../payments/payment-polling.service';
import { BusinessService } from '../../business/business.service';
import { CartsService } from './carts.service';
import { OrderEventsService } from './order-events.service';

@Injectable()
export class OrdersService {
  private readonly logger = new Logger(OrdersService.name);

  constructor(
    private readonly prisma: PrismaService,
    private readonly connectorFactory: ConnectorFactory,
    private readonly paymentFactory: PaymentFactory,
    private readonly paymentPollingService: PaymentPollingService,
    private readonly businessService: BusinessService,
    private readonly cartsService: CartsService,
    private readonly orderEventsService: OrderEventsService,
  ) {}

  async listOrders(businessId: string) {
    return this.prisma.order.findMany({
      where: { businessId },
      include: {
        customer: true,
        payments: true,
        items: true,
      },
      orderBy: { createdAt: 'desc' },
    });
  }

  async getOrder(orderId: string) {
    return this.prisma.order.findUnique({
      where: { id: orderId },
      include: {
        customer: true,
        payments: true,
        items: true,
      },
    });
  }

  async createOrderFromCart(
    businessId: string,
    whatsappNumber: string,
    customerName: string,
    deliveryMethod: string,
    deliveryAddress?: string,
    deliveryLat?: number,
    deliveryLng?: number,
  ) {
    // 1. Fetch Cart
    const cart = await this.prisma.cart.findFirst({
      where: { businessId, whatsappNumber, status: 'ACTIVE' },
      include: {
        items: {
          include: {
            product: true,
            variant: true,
          },
        },
      },
    });

    if (!cart || cart.items.length === 0) {
      throw new BadRequestException('Your cart is empty.');
    }

    // 2. Fetch or Create Customer
    let customer = await this.prisma.customer.findFirst({
      where: { businessId, whatsappNumber },
    });

    if (!customer) {
      customer = await this.prisma.customer.create({
        data: {
          businessId,
          whatsappNumber,
          name: customerName,
        },
      });
    } else if (customerName && customer.name !== customerName) {
      customer = await this.prisma.customer.update({
        where: { id: customer.id },
        data: { name: customerName },
      });
    }

    // If deliveryAddress contains a Google Maps link and lat/lng are missing, resolve automatically
    let resolvedLat = deliveryLat ?? null;
    let resolvedLng = deliveryLng ?? null;
    if (deliveryAddress && (resolvedLat === null || resolvedLng === null)) {
      const coords = await this.resolveGoogleMapsCoordinates(deliveryAddress);
      if (coords.lat !== null && coords.lng !== null) {
        resolvedLat = coords.lat;
        resolvedLng = coords.lng;
      }
    }

    // 3. Create Internal Order in SQLite
    const orderNumber = `ORD-${Math.floor(100000 + Math.random() * 900000)}`;
    const order = await this.prisma.order.create({
      data: {
        businessId,
        customerId: customer.id,
        sourceChannel: 'whatsapp',
        sourceSystem: 'woocommerce',
        orderNumber,
        status: 'PENDING',
        paymentStatus: 'UNPAID',
        totalAmount: cart.totalAmount,
        currency: cart.currency,
        customerPhone: whatsappNumber,
        customerName: customerName || 'WhatsApp Customer',
        deliveryMethod,
        deliveryAddress,
        deliveryLat: resolvedLat,
        deliveryLng: resolvedLng,
        items: {
          create: cart.items.map((item) => ({
            productId: item.productId,
            variantId: item.variantId,
            externalProductId: item.product.externalProductId,
            externalVariantId: item.variant?.externalVariantId || null,
            productName: item.variant ? `${item.product.name} (${item.variant.name})` : item.product.name,
            quantity: item.quantity,
            unitPrice: item.unitPrice,
            lineTotal: item.lineTotal,
          })),
        },
      },
      include: {
        items: true,
      },
    });

    // 4. Create External Order in WooCommerce (using Connector) in background
    this.syncOrderToWooCommerce(order.id, businessId).catch((err) => {
      this.logger.error(`Unexpected background order sync error for order ${order.id}: ${err.message}`);
    });

    // Broadcast order creation event via SSE
    this.orderEventsService.emitOrderUpdate(businessId, {
      type: 'order_created',
      orderId: order.id,
      orderNumber: order.orderNumber,
      status: order.status,
    });

    // 5. Generate Payment Link (Payment Gateway)
    let paymentLink = '';
    let paymentReference = '';
    let gatewayRef = '';

    // Determine gateway. If merchant has Paynow details, use Paynow. Otherwise Mock.
    // For Sandbox integration we always use 'mock'.
    let gatewayType = 'mock';
    let gatewayCreds: Record<string, any> = { isSandbox: true };

    // Try to find if Paynow/PesePay integration credentials exist.
    // In our simplified MVP, we use 'mock' by default unless configured.
    const paynowConfig = await this.prisma.businessIntegration.findFirst({
      where: { businessId, integrationType: 'paynow', status: 'ACTIVE' },
    });
    if (paynowConfig) {
      gatewayType = 'paynow';
      gatewayCreds = await this.businessService.getDecryptedCredentials(businessId, 'paynow') || {};
    } else {
      const pesepayConfig = await this.prisma.businessIntegration.findFirst({
        where: { businessId, integrationType: 'pesepay', status: 'ACTIVE' },
      });
      if (pesepayConfig) {
        gatewayType = 'pesepay';
        gatewayCreds = await this.businessService.getDecryptedCredentials(businessId, 'pesepay') || {};
      }
    }

    try {
      const gateway = this.paymentFactory.getGateway(gatewayType, gatewayCreds);
      
      const callbackUrl = `${process.env.BACKEND_URL || 'http://localhost:3001'}/webhooks/payments/${gatewayType}`;
      
      const payResult = await gateway.createPaymentLink(
        order.id,
        order.totalAmount,
        order.currency,
        customer.email || 'customer@whatsappcommerce.com',
        callbackUrl,
      );

      paymentLink = payResult.paymentLink;
      paymentReference = payResult.paymentReference;
      gatewayRef = payResult.gatewayReference || '';

      // Create Payment Record in local DB
      await this.prisma.payment.create({
        data: {
          businessId,
          orderId: order.id,
          gateway: gatewayType,
          paymentReference,
          gatewayReference: gatewayRef,
          amount: order.totalAmount,
          currency: order.currency,
          status: 'PENDING',
          paymentLink,
        },
      });
    } catch (payErr: any) {
      this.logger.error(`Failed to generate payment link: ${payErr.message}`);
      // Create a local payment record even if gateway failed, fallback to manual checkout
      paymentReference = `PAY-MANUAL-${order.id}`;
      paymentLink = '#';
    }

    // 6. Clear Cart
    await this.cartsService.clearCart(cart.id);

    // 7. Notify store owner
    try {
      await this.paymentPollingService.notifyOwner(
        businessId,
        order.orderNumber,
        order.customerName || 'WhatsApp Customer',
        order.customerPhone,
        order.totalAmount,
        order.currency,
        'UNPAID',
      );
    } catch (err: any) {
      this.logger.error(`Failed to notify store owner in createOrderFromCart: ${err.message}`);
    }

    return {
      orderId: order.id,
      orderNumber: order.orderNumber,
      externalOrderNumber: order.orderNumber,
      totalAmount: order.totalAmount,
      currency: order.currency,
      paymentLink,
      paymentReference,
    };
  }

  async confirmPayment(paymentReference: string, status: 'SUCCESS' | 'FAILED', gatewayReference?: string) {
    this.logger.log(`Processing payment webhook: ref=${paymentReference}, status=${status}`);

    const payment = await this.prisma.payment.findUnique({
      where: { paymentReference },
      include: {
        order: {
          include: {
            customer: true,
            items: true,
          },
        },
      },
    });

    if (!payment) {
      throw new NotFoundException(`Payment record with reference ${paymentReference} not found`);
    }

    if (payment.status === 'SUCCESS') {
      this.logger.warn(`Payment with reference ${paymentReference} is already SUCCESS. Skipping.`);
      return payment.order;
    }

    // 1. Update Payment Status
    await this.prisma.payment.update({
      where: { id: payment.id },
      data: {
        status: status === 'SUCCESS' ? 'SUCCESS' : 'FAILED',
        gatewayReference: gatewayReference || payment.gatewayReference,
      },
    });

    // 2. Update Order Status
    const orderStatus = status === 'SUCCESS' ? 'PROCESSING' : 'PENDING';
    const paymentStatus = status === 'SUCCESS' ? 'PAID' : 'FAILED';

    const updatedOrder = await this.prisma.order.update({
      where: { id: payment.orderId },
      data: {
        status: orderStatus,
        paymentStatus,
      },
      include: {
        customer: true,
      },
    });

    // Broadcast order update event via SSE
    this.orderEventsService.emitOrderUpdate(payment.businessId, {
      type: 'order_updated',
      orderId: updatedOrder.id,
      orderNumber: updatedOrder.orderNumber,
      status: updatedOrder.status,
    });

    // Deduct stock for successful payments
    if (status === 'SUCCESS') {
      for (const item of payment.order.items) {
        try {
          if (item.variantId) {
            const variant = await this.prisma.productVariant.findUnique({
              where: { id: item.variantId },
            });
            if (variant && variant.stockQuantity !== null) {
              const newStock = Math.max(0, variant.stockQuantity - item.quantity);
              await this.prisma.productVariant.update({
                where: { id: item.variantId },
                data: { stockQuantity: newStock },
              });
              this.logger.log(`Deducted variant ${item.variantId} stock by ${item.quantity} (New: ${newStock})`);
              this.syncStockToIntegration(payment.businessId, item.productId, newStock, item.variantId).catch((err) => {
                this.logger.error(`Failed to sync variant stock to WooCommerce: ${err.message}`);
              });
            }
          } else {
            const product = await this.prisma.product.findUnique({
              where: { id: item.productId },
            });
            if (product && product.stockQuantity !== null) {
              const newStock = Math.max(0, product.stockQuantity - item.quantity);
              await this.prisma.product.update({
                where: { id: item.productId },
                data: { stockQuantity: newStock },
              });
              this.logger.log(`Deducted product ${item.productId} stock by ${item.quantity} (New: ${newStock})`);
              this.syncStockToIntegration(payment.businessId, item.productId, newStock).catch((err) => {
                this.logger.error(`Failed to sync product stock to WooCommerce: ${err.message}`);
              });
            }
          }
        } catch (err: any) {
          this.logger.error(`Failed to deduct stock for item ${item.id}: ${err.message}`);
        }
      }
    }

    // 3. Update WooCommerce Order Status (using Connector) in background
    if (updatedOrder.externalOrderId) {
      this.syncPaymentStatusToWooCommerce(
        updatedOrder.businessId,
        updatedOrder.externalOrderId,
        paymentStatus,
        gatewayReference || paymentReference
      ).catch((err) => {
        this.logger.error(`Failed to sync payment status to WooCommerce in background: ${err.message}`);
      });
    }

    // Clear the customer's session if they are waiting for payment
    try {
      const session = await this.prisma.session.findFirst({
        where: {
          businessId: payment.businessId,
          whatsappNumber: payment.order.customerPhone,
        },
      });
      if (session && session.currentStep === 'AWAITING_PAYMENT') {
        await this.prisma.session.update({
          where: { id: session.id },
          data: {
            currentStep: 'WELCOME',
            sessionDataJson: '{}',
          },
        });
        this.logger.log(`Cleared AWAITING_PAYMENT session for customer ${payment.order.customerPhone}`);
      }
    } catch (err: any) {
      this.logger.error(`Failed to clear customer session: ${err.message}`);
    }

    // Notify store owner
    try {
      await this.paymentPollingService.notifyOwner(
        payment.businessId,
        updatedOrder.orderNumber,
        updatedOrder.customerName,
        updatedOrder.customerPhone,
        updatedOrder.totalAmount,
        updatedOrder.currency,
        status === 'SUCCESS' ? 'DONE' : 'UNPAID',
      );
    } catch (err: any) {
      this.logger.error(`Failed to notify store owner in confirmPayment: ${err.message}`);
    }

    // Notify customer on WhatsApp with receipt or failed alert
    try {
      if (status === 'SUCCESS') {
        let receipt = `🧾 *OFFICIAL RECEIPT*\n`;
        receipt += `--------------------------------\n`;
        receipt += `*Order:* ${updatedOrder.orderNumber}\n`;
        receipt += `*Date:* ${new Date().toLocaleDateString()}\n`;
        receipt += `*Customer:* ${updatedOrder.customerName}\n`;
        receipt += `*Delivery:* ${updatedOrder.deliveryMethod === 'delivery' ? 'Home Delivery' : 'Store Pickup'}\n`;
        if (updatedOrder.deliveryAddress && updatedOrder.deliveryMethod === 'delivery') {
          receipt += `*Address:* ${updatedOrder.deliveryAddress}\n`;
        }
        receipt += `--------------------------------\n`;
        receipt += `*Items Ordered:*\n`;
        
        payment.order.items.forEach((item, index) => {
          receipt += `${index + 1}. *${item.productName}*\n`;
          receipt += `   Qty: ${item.quantity} x $${item.unitPrice.toFixed(2)} = *$${item.lineTotal.toFixed(2)}*\n`;
        });
        
        receipt += `--------------------------------\n`;
        receipt += `*Payment Method:* ${payment.gateway.toUpperCase()}\n`;
        receipt += `*Transaction Ref:* ${paymentReference}\n`;
        receipt += `*Status:* PAID ✅\n`;
        receipt += `*Total Amount:* *${updatedOrder.currency} $${updatedOrder.totalAmount.toFixed(2)}*\n`;
        receipt += `--------------------------------\n`;
        receipt += `Thank you for shopping with us! Reply *menu* to return to the main menu.`;

        await this.paymentPollingService.notify(
          payment.businessId,
          updatedOrder.customerPhone,
          receipt,
        );
      } else {
        const failedMessage = `⚠️ *Payment Failed / Cancelled*\n\n` +
          `Your payment of *${updatedOrder.currency} $${updatedOrder.totalAmount.toFixed(2)}* for Order *${updatedOrder.orderNumber}* could not be processed.\n` +
          `Reference: *${paymentReference}*\n\n` +
          `Please try again. Reply *menu* to go back to the shop.`;

        await this.paymentPollingService.notify(
          payment.businessId,
          updatedOrder.customerPhone,
          failedMessage,
        );
      }
    } catch (err: any) {
      this.logger.error(`Failed to send WhatsApp notification to customer: ${err.message}`);
    }

    // 4. Trigger Outbound Notification
    // We emit an event or call the WhatsApp bot dispatcher to send the confirmation.
    // The WhatsApp Module will catch this and send a message.
    return updatedOrder;
  }

  async verifyAndConfirmPayment(paymentReference: string) {
    const payment = await this.prisma.payment.findUnique({
      where: { paymentReference },
      include: {
        order: true,
      },
    });

    if (!payment) {
      this.logger.warn(`Payment record with reference ${paymentReference} not found`);
      return null;
    }

    if (payment.status === 'SUCCESS') {
      return payment.order;
    }

    const gatewayType = payment.gateway;
    let gatewayCreds = {};
    if (gatewayType !== 'mock') {
      gatewayCreds = await this.businessService.getDecryptedCredentials(payment.businessId, gatewayType) || {};
    }

    try {
      const gateway = this.paymentFactory.getGateway(gatewayType, gatewayCreds);
       const lookupRef = (gatewayType === 'paynow' ? payment.gatewayReference : paymentReference) || paymentReference;
       const verifyResult = await gateway.verifyPayment(lookupRef);

      if (verifyResult.status === 'SUCCESS') {
        return this.confirmPayment(paymentReference, 'SUCCESS', verifyResult.gatewayReference);
      } else if (verifyResult.status === 'FAILED') {
        return this.confirmPayment(paymentReference, 'FAILED', verifyResult.gatewayReference);
      }
    } catch (err: any) {
      this.logger.error(`Error verifying payment ${paymentReference}: ${err.message}`);
    }

    return null;
  }

  /**
   * Initiates a seamless EcoCash push payment via PesePay after the customer provides their number.
   * Called from the bot engine after the CHECKOUT_ECOCASH step.
   */
  async initiateSeamlessPayment(
    businessId: string,
    orderId: string,
    whatsappNumber: string,
    ecocashNumber: string,
  ): Promise<{ paymentReference: string; amount: number; currency: string }> {
    const order = await this.prisma.order.findFirst({
      where: { id: orderId, businessId },
      include: { customer: true },
    });

    if (!order) throw new NotFoundException(`Order ${orderId} not found`);

    // Determine which gateway to use
    let gatewayType = 'mock';
    let gatewayCreds: Record<string, any> = { isSandbox: true };

    // Fallback to process.env credentials if present
    if (process.env.PESEPAY_INTEGRATION_KEY && process.env.PESEPAY_ENCRYPTION_KEY) {
      gatewayType = 'pesepay';
      gatewayCreds = {
        pesepayMerchantKey: process.env.PESEPAY_INTEGRATION_KEY,
        pesepayEncryptionKey: process.env.PESEPAY_ENCRYPTION_KEY,
        isSandbox: process.env.PESEPAY_SANDBOX === 'true',
      };
    }

    const pesepayConfig = await this.prisma.businessIntegration.findFirst({
      where: { businessId, integrationType: 'pesepay', status: 'ACTIVE' },
    });
    if (pesepayConfig) {
      gatewayType = 'pesepay';
      gatewayCreds = (await this.businessService.getDecryptedCredentials(businessId, 'pesepay')) || {};
    }

    const callbackUrl = `${process.env.PUBLIC_URL || 'http://localhost:3001'}/webhooks/payments/${gatewayType}`;
    const gateway = this.paymentFactory.getGateway(gatewayType, gatewayCreds);

    const result = await gateway.makeSeamlessPayment(
      orderId,
      order.totalAmount,
      order.currency,
      ecocashNumber,
      order.customer?.email || 'customer@whatsappcommerce.com',
      `Order ${order.orderNumber} via WhatsApp Commerce Hub`,
      callbackUrl,
    );

    const paymentReference = result.paymentReference;

    // Save payment record
    await this.prisma.payment.create({
      data: {
        businessId,
        orderId: order.id,
        gateway: gatewayType,
        paymentReference,
        gatewayReference: result.gatewayReference || result.pollUrl || '',
        amount: order.totalAmount,
        currency: order.currency,
        status: 'PENDING',
        paymentLink: '',
      },
    });

    // Update order to awaiting payment
    await this.prisma.order.update({
      where: { id: orderId },
      data: { paymentStatus: 'UNPAID', status: 'PENDING' },
    });

    // Start background polling (non-blocking)
    this.paymentPollingService.startPolling({
      paymentReference,
      orderId,
      businessId,
      whatsappNumber,
    });

    // Notify store owner
    try {
      await this.paymentPollingService.notifyOwner(
        businessId,
        order.orderNumber,
        order.customerName || 'WhatsApp Customer',
        order.customerPhone,
        order.totalAmount,
        order.currency,
        'UNPAID',
      );
    } catch (err: any) {
      this.logger.error(`Failed to notify store owner in initiateSeamlessPayment: ${err.message}`);
    }

    this.logger.log(`Seamless EcoCash payment initiated: ref=${paymentReference}, gateway=${gatewayType}, orderId=${orderId}`);
    return { paymentReference, amount: order.totalAmount, currency: order.currency };
  }

  async updateOrderStatus(businessId: string, orderId: string, status: string) {
    const order = await this.prisma.order.findFirst({
      where: { id: orderId, businessId },
    });

    if (!order) {
      throw new NotFoundException('Order not found');
    }

    const updated = await this.prisma.order.update({
      where: { id: orderId },
      data: { status },
    });

    // Broadcast order update event via SSE
    this.orderEventsService.emitOrderUpdate(businessId, {
      type: 'order_updated',
      orderId: updated.id,
      orderNumber: updated.orderNumber,
      status: updated.status,
    });

    // Update WooCommerce status
    if (order.externalOrderId) {
      try {
        const integration = await this.prisma.businessIntegration.findFirst({
          where: { businessId, integrationType: 'woocommerce', status: 'ACTIVE' },
        });
        if (integration) {
          const credentials = await this.businessService.getDecryptedCredentials(businessId, integration.integrationType);
          if (credentials) {
            const connector = this.connectorFactory.getConnector(integration.integrationType, credentials);
            await connector.updateOrderStatus(order.externalOrderId, status);
          }
        }
      } catch (err: any) {
        this.logger.error(`Failed to update WooCommerce status: ${err.message}`);
      }
    }

    return updated;
  }

  async listCustomers(businessId: string) {
    const customers = await this.prisma.customer.findMany({
      where: { businessId },
      include: {
        orders: {
          select: {
            totalAmount: true,
            status: true,
            paymentStatus: true,
            createdAt: true,
            orderNumber: true,
          }
        }
      },
      orderBy: { name: 'asc' },
    });

    return customers.map(customer => {
      const PROCESSED_STATUSES = ['PROCESSING', 'COMPLETED', 'DELIVERED'];
      const successfulOrders = customer.orders.filter(
        o => o.paymentStatus === 'PAID' && PROCESSED_STATUSES.includes(o.status)
      );
      const totalSpent = successfulOrders.reduce((sum, o) => sum + o.totalAmount, 0);
      
      return {
        id: customer.id,
        name: customer.name || 'WhatsApp Customer',
        whatsappNumber: customer.whatsappNumber,
        createdAt: customer.createdAt,
        totalOrders: successfulOrders.length,
        totalSpent,
        orders: customer.orders.map(o => ({
          orderNumber: o.orderNumber,
          totalAmount: o.totalAmount,
          status: o.status,
          paymentStatus: o.paymentStatus,
          createdAt: o.createdAt,
        }))
      };
    });
  }

  private async syncOrderToWooCommerce(orderId: string, businessId: string) {
    try {
      const order = await this.prisma.order.findUnique({
        where: { id: orderId },
        include: { items: true },
      });
      if (!order) return;

      const integration = await this.prisma.businessIntegration.findFirst({
        where: { businessId, integrationType: 'woocommerce', status: 'ACTIVE' },
      });

      if (!integration) return;

      const credentials = await this.businessService.getDecryptedCredentials(businessId, integration.integrationType);
      if (!credentials) return;

      const connector = this.connectorFactory.getConnector(integration.integrationType, credentials);
      const wcOrderResult = await connector.createOrder({
        customerName: order.customerName,
        customerPhone: order.customerPhone,
        deliveryAddress: order.deliveryAddress || undefined,
        totalAmount: order.totalAmount,
        currency: order.currency,
        items: order.items.map((item) => ({
          externalProductId: item.externalProductId || '',
          externalVariantId: item.externalVariantId || undefined,
          productName: item.productName,
          quantity: item.quantity,
          unitPrice: item.unitPrice,
          lineTotal: item.lineTotal,
        })),
      });

      await this.prisma.order.update({
        where: { id: order.id },
        data: {
          externalOrderId: wcOrderResult.externalOrderId,
          sourceSystem: integration.integrationType,
        },
      });
      this.logger.log(`Synced order ${order.orderNumber} to WooCommerce successfully as external ID: ${wcOrderResult.externalOrderId}`);
    } catch (wcErr: any) {
      this.logger.error(`Failed to sync order ${orderId} creation to WooCommerce in background: ${wcErr.message}`);
    }
  }

  private async syncPaymentStatusToWooCommerce(
    businessId: string,
    externalOrderId: string,
    paymentStatus: 'PAID' | 'FAILED',
    paymentReference: string,
  ) {
    try {
      const integration = await this.prisma.businessIntegration.findFirst({
        where: { businessId, integrationType: 'woocommerce', status: 'ACTIVE' },
      });

      if (integration) {
        const credentials = await this.businessService.getDecryptedCredentials(businessId, integration.integrationType);
        if (credentials) {
          const connector = this.connectorFactory.getConnector(integration.integrationType, credentials);
          await connector.updatePaymentStatus(
            externalOrderId,
            paymentStatus,
            paymentReference,
          );
          this.logger.log(`Updated WooCommerce order ${externalOrderId} payment status to ${paymentStatus} in background`);
        }
      }
    } catch (wcErr: any) {
      this.logger.error(`Failed to update order status in WooCommerce in background: ${wcErr.message}`);
    }
  }

  private async syncStockToIntegration(
    businessId: string,
    productId: string,
    newStock: number,
    variantId?: string,
  ) {
    try {
      const integration = await this.prisma.businessIntegration.findFirst({
        where: { businessId, integrationType: 'woocommerce', status: 'ACTIVE' },
      });
      if (!integration) return;

      const product = await this.prisma.product.findUnique({
        where: { id: productId },
      });
      if (!product || !product.externalProductId) return;

      let extVariantId: string | undefined;
      if (variantId) {
        const variant = await this.prisma.productVariant.findUnique({
          where: { id: variantId },
        });
        if (variant && variant.externalVariantId) {
          extVariantId = variant.externalVariantId;
        }
      }

      const credentials = await this.businessService.getDecryptedCredentials(businessId, integration.integrationType);
      if (credentials) {
        const connector = this.connectorFactory.getConnector(integration.integrationType, credentials);
        await connector.updateStock(
          product.externalProductId,
          newStock,
          extVariantId,
        );
        this.logger.log(`Synced stock update for product ${product.id} to WooCommerce (New: ${newStock})`);
      }
    } catch (wcErr: any) {
      this.logger.error(`Failed to sync stock update to WooCommerce in background: ${wcErr.message}`);
    }
  }

  private async resolveGoogleMapsCoordinates(addressInput?: string): Promise<{ lat: number | null; lng: number | null }> {
    if (!addressInput) return { lat: null, lng: null };

    const urlMatch = addressInput.match(/(https?:\/\/[^\s]+)/gi);
    if (!urlMatch) return { lat: null, lng: null };

    const targetUrl = urlMatch[0];
    try {
      let finalUrl = targetUrl;
      if (targetUrl.includes('goo.gl') || targetUrl.includes('maps.app.goo.gl') || targetUrl.includes('page.link')) {
        const res = await fetch(targetUrl, { method: 'GET', redirect: 'follow' });
        finalUrl = res.url;
      }

      // Pattern A: !3d-17.7921137!4d31.0992914
      const p1 = finalUrl.match(/!3d(-?\d+\.\d+)!4d(-?\d+\.\d+)/);
      if (p1) {
        return { lat: parseFloat(p1[1]), lng: parseFloat(p1[2]) };
      }

      // Pattern B: /@-17.7921137,31.0992914
      const p2 = finalUrl.match(/@(-?\d+\.\d+),(-?\d+\.\d+)/);
      if (p2) {
        return { lat: parseFloat(p2[1]), lng: parseFloat(p2[2]) };
      }

      // Pattern C: ?q=-17.7921137,31.0992914 or ?ll=-17.7921137,31.0992914
      const p3 = finalUrl.match(/[?&](?:q|ll)=(-?\d+\.\d+),(-?\d+\.\d+)/);
      if (p3) {
        return { lat: parseFloat(p3[1]), lng: parseFloat(p3[2]) };
      }
    } catch (err) {
      this.logger.warn(`Failed to resolve Google Maps URL: ${err}`);
    }

    return { lat: null, lng: null };
  }
}
