import { Injectable, Logger } from '@nestjs/common';
import { WhatsAppSessionService, SessionData } from './whatsapp-session.service';
import { CartsService } from '../../commerce/services/carts.service';
import { ProductsService } from '../../commerce/services/products.service';
import { OrdersService } from '../../commerce/services/orders.service';
import { PrismaService } from '../../../prisma/prisma.service';

export interface BotResponse {
  text: string;
  payload?: {
    type: 'button_grid' | 'pills' | 'product_carousel' | 'product_detail' | 'cta_url' | 'interactive';
    interactive?: any;
    buttons?: Array<{ id: string; title: string; icon?: string; color?: string }>;
    options?: Array<{ id: string; title: string; icon?: string }>;
    products?: Array<{
      id: string;
      name: string;
      description?: string;
      price: number;
      imageUrl?: string;
      rating?: number;
    }>;
    product?: {
      name: string;
      description?: string;
      price: number;
      imageUrl?: string;
    };
    // For cta_url type
    url?: string;
    urlButtonText?: string;
    buttonText?: string;
    // Optional follow-up quick replies shown after the CTA
    followUpOptions?: Array<{ id: string; title: string; icon?: string }>;
  };
}

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

  constructor(
    private readonly prisma: PrismaService,
    private readonly sessionService: WhatsAppSessionService,
    private readonly cartsService: CartsService,
    private readonly productsService: ProductsService,
    private readonly ordersService: OrdersService,
  ) { }

  async processMessage(
    businessId: string,
    whatsappNumber: string,
    messageBody: string,
  ): Promise<BotResponse> {
    const cleanMessage = messageBody.trim();

    // Look up any existing session by whatsappNumber first to determine active businessId
    let session = await this.prisma.session.findFirst({
      where: { whatsappNumber },
    });

    const isExpired = session ? session.expiresAt < new Date() : true;
    const activeBusinessId = (session && !isExpired) ? session.businessId : businessId;

    // Find or create customer under the active business
    let customer = await this.prisma.customer.findFirst({
      where: { businessId: activeBusinessId, whatsappNumber },
    });

    if (!customer) {
      customer = await this.prisma.customer.create({
        data: {
          businessId: activeBusinessId,
          whatsappNumber,
          name: 'WhatsApp Customer',
        },
      });
    }

    // Get or initialize active session
    session = await this.sessionService.getOrCreateSession(activeBusinessId, whatsappNumber, customer.id);
    const step = session.currentStep;

    let sessionData: SessionData = {};
    try {
      sessionData = JSON.parse(session.sessionDataJson);
    } catch {
      sessionData = {};
    }

    this.logger.log(`Processing bot message: phone=${whatsappNumber}, step=${step}, businessId=${session.businessId}, input="${cleanMessage}"`);

    // Global interceptors (e.g. exit support or reset bot)
    const welcomeTriggers = ['hi', 'hie', 'hello', 'menu', 'whatsapp', 'reset'];
    if (welcomeTriggers.includes(cleanMessage.toLowerCase())) {
      const activeBusinessesCount = await this.prisma.business.count({
        where: { status: 'ACTIVE' },
      });
      await this.sessionService.clearSession(session.id);
      if (activeBusinessesCount > 1) {
        return this.promptStoreSelection(session.id);
      }
      return this.getWelcomeMessage(session.businessId);
    }

    if (cleanMessage.toLowerCase() === 'support' || cleanMessage.toLowerCase() === 'talk to support') {
      await this.sessionService.updateStep(session.id, 'SUPPORT');
      return {
        text: `*Customer Support*\n\nHow would you like to contact Quatrohaus Support?\n\n1. Call Quatrohaus\n2. Message Quatrohaus\n3. Exit Support`,
        payload: {
          type: 'pills',
          options: [
            { id: '1', title: 'Call Quatrohaus' },
            { id: '2', title: 'Message Quatrohaus' },
            { id: '3', title: 'Exit Support' }
          ]
        }
      };
    }

    switch (step) {
      case 'SELECT_STORE':
        return this.handleSelectStoreStep(session.id, whatsappNumber, cleanMessage);

      case 'WELCOME':
        return this.handleWelcomeStep(session.id, session.businessId, whatsappNumber, cleanMessage);

      case 'BROWSE_CATEGORIES':
        return this.handleBrowseCategoriesStep(session.id, session.businessId, sessionData, cleanMessage);

      case 'BROWSE_PRODUCTS':
        return this.handleBrowseProductsStep(session.id, session.businessId, sessionData, cleanMessage);

      case 'PRODUCT_DETAILS':
        return this.handleProductDetailsStep(session.id, session.businessId, whatsappNumber, sessionData, cleanMessage);

      case 'POST_ADD_TO_CART':
        return this.handlePostAddToCartStep(session.id, session.businessId, whatsappNumber, sessionData, cleanMessage);

      case 'ADD_MORE_QUANTITY':
        return this.handleAddMoreQuantityStep(session.id, session.businessId, whatsappNumber, sessionData, cleanMessage);

      case 'SEARCH_PRODUCTS':
        return this.handleSearchProductsStep(session.id, session.businessId, cleanMessage);

      case 'CART':
        return this.handleCartStep(session.id, session.businessId, whatsappNumber, cleanMessage);

      case 'CHECKOUT_NAME':
        return this.handleCheckoutNameStep(session.id, session.businessId, sessionData, cleanMessage);

      case 'CHECKOUT_DELIVERY':
        return this.handleCheckoutDeliveryStep(session.id, sessionData, cleanMessage);

      case 'CHECKOUT_ADDRESS':
        return this.handleCheckoutAddressStep(session.id, session.businessId, whatsappNumber, sessionData, cleanMessage);

      case 'CHECKOUT_CONFIRM':
        return this.handleCheckoutConfirmStep(session.id, session.businessId, whatsappNumber, sessionData, cleanMessage);

      case 'CHECKOUT_ECOCASH':
        return this.handleCheckoutEcoCashStep(session.id, session.businessId, whatsappNumber, sessionData, cleanMessage);

      case 'AWAITING_PAYMENT':
        return this.handleAwaitingPaymentStep(session.id, session.businessId, whatsappNumber, sessionData, cleanMessage);

      case 'SUPPORT':
        return this.handleSupportStep(session.id, session.businessId, cleanMessage);

      default:
        await this.sessionService.clearSession(session.id);
        return this.getWelcomeMessage(session.businessId);
    }
  }

  // --- STORE SELECTION STEP ---
  private async promptStoreSelection(sessionId: string): Promise<BotResponse> {
    const activeBusinesses = await this.prisma.business.findMany({
      where: { status: 'ACTIVE' },
      orderBy: { name: 'asc' },
    });

    let response = `*Select a store to continue:*\n\n`;
    const pills: Array<{ id: string; title: string }> = [];
    activeBusinesses.forEach((biz, index) => {
      response += `${index + 1}. ${biz.name}\n`;
      pills.push({ id: String(index + 1), title: biz.name });
    });
    response += `\nReply with the number of your choice.`;

    await this.sessionService.updateStep(sessionId, 'SELECT_STORE');

    return {
      text: response,
      payload: {
        type: 'pills',
        options: pills,
      },
    };
  }

  private async handleSelectStoreStep(
    sessionId: string,
    whatsappNumber: string,
    input: string,
  ): Promise<BotResponse> {
    const activeBusinesses = await this.prisma.business.findMany({
      where: { status: 'ACTIVE' },
      orderBy: { name: 'asc' },
    });

    const index = parseInt(input) - 1;
    if (isNaN(index) || index < 0 || index >= activeBusinesses.length) {
      const isInvalidNumber = !isNaN(index);
      let response = isInvalidNumber
        ? `Invalid option. Please select a valid store:\n\n`
        : `*Select a store to continue:*\n\n`;
        
      const pills: Array<{ id: string; title: string }> = [];
      activeBusinesses.forEach((biz, index) => {
        response += `${index + 1}. ${biz.name}\n`;
        pills.push({ id: String(index + 1), title: biz.name });
      });
      response += `\nReply with the number of your choice.`;

      return {
        text: response,
        payload: {
          type: 'pills',
          options: pills,
        },
      };
    }

    const selectedBiz = activeBusinesses[index];

    // Find or create customer under the selected business
    let customer = await this.prisma.customer.findFirst({
      where: { businessId: selectedBiz.id, whatsappNumber },
    });

    if (!customer) {
      customer = await this.prisma.customer.create({
        data: {
          businessId: selectedBiz.id,
          whatsappNumber,
          name: 'WhatsApp Customer',
        },
      });
    }

    // Update session's businessId, customerId and set step to WELCOME
    await this.prisma.session.update({
      where: { id: sessionId },
      data: {
        businessId: selectedBiz.id,
        customerId: customer.id,
        currentStep: 'WELCOME',
      },
    });

    // Return welcome message for the selected business
    return this.getWelcomeMessage(selectedBiz.id);
  }

  // --- WELCOME STEP ---
  private async getWelcomeMessage(businessId: string): Promise<BotResponse> {
    const business = await this.prisma.business.findUnique({ where: { id: businessId } });
    const name = business?.name || 'our Store';

    // Check active businesses count
    const activeBusinessesCount = await this.prisma.business.count({
      where: { status: 'ACTIVE' },
    });

    let text = `Welcome to *${name}* Shopping Bot!\n\n` +
      `This is View Cart, Shop Now, Talk to Support and Search Products. Reply with a number:\n\n` +
      `1. Shop Now\n` +
      `2. Search Products\n` +
      `3. View Cart\n` +
      `4. Talk to Support`;

    const buttons = [
      { id: '1', title: 'Shop Now', color: 'emerald', icon: 'icons8-box.svg' },
      { id: '2', title: 'Search Products', color: 'cyan', icon: 'icons8-list.svg' },
      { id: '3', title: 'View Cart', color: 'amber', icon: 'icons8-cart.svg' },
      { id: '4', title: 'Talk to Support', color: 'purple', icon: 'icons8-user.svg' }
    ];

    if (activeBusinessesCount > 1) {
      text += `\n5. Change Store`;
      buttons.push({ id: '5', title: 'Change Store', color: 'gray', icon: 'icons8-settings.svg' });
    }

    text += `\n\n_Type "menu" or "reset" at any time to return here._`;

    return {
      text,
      payload: {
        type: 'button_grid',
        buttons
      }
    };
  }

  private async handleWelcomeStep(
    sessionId: string,
    businessId: string,
    whatsappNumber: string,
    input: string,
  ): Promise<BotResponse> {
    const cleanInput = input.trim().toLowerCase();

    if (cleanInput === '1' || cleanInput.includes('shop') || cleanInput.includes('browse')) {
      const categories = await this.productsService.listCategories(businessId);
      if (categories.length === 0) {
        return {
          text: `We don't have any categories configured yet. Type "2" to search products, or "menu" to go back.`,
          payload: {
            type: 'pills',
            options: [{ id: 'B', title: 'Back to Menu' }]
          }
        };
      }

      let response = `*Select a category to browse:*\n\n`;
      const catIds: string[] = [];
      const pills: Array<{ id: string; title: string }> = [];
      const categoriesToDisplay = categories.slice(0, 9);

      categoriesToDisplay.forEach((cat, index) => {
        response += `${index + 1}. ${cat.name}\n`;
        catIds.push(cat.id);
        pills.push({ id: String(index + 1), title: cat.name });
      });
      response += `\nReply with the category number (e.g. 1) or type *B* to go back.`;
      pills.push({ id: 'B', title: 'Back to Menu' });

      await this.sessionService.updateStep(sessionId, 'BROWSE_CATEGORIES');
      await this.sessionService.updateSessionData(sessionId, { lastCategoryList: catIds });
      return {
        text: response,
        payload: {
          type: 'pills',
          options: pills
        }
      };
    }

    if (cleanInput === '2' || cleanInput.includes('search')) {
      await this.sessionService.updateStep(sessionId, 'SEARCH_PRODUCTS');
      return {
        text: `*Search Products*\n\nType the product name or details you are looking for:`,
        payload: {
          type: 'pills',
          options: [{ id: 'B', title: 'Back to Menu' }]
        }
      };
    }

    if (cleanInput === '3' || cleanInput.includes('cart') || cleanInput.includes('basket')) {
      return this.printCart(businessId, whatsappNumber);
    }

    if (cleanInput === '4' || cleanInput.includes('support') || cleanInput.includes('talk')) {
      await this.sessionService.updateStep(sessionId, 'SUPPORT');
      return {
        text: `*Customer Support*\n\nHow would you like to contact Quatrohaus Support?\n\n1. Call Quatrohaus\n2. Message Quatrohaus\n3. Exit Support`,
        payload: {
          type: 'pills',
          options: [
            { id: '1', title: 'Call Quatrohaus' },
            { id: '2', title: 'Message Quatrohaus' },
            { id: '3', title: 'Exit Support' }
          ]
        }
      };
    }

    if (cleanInput === '5' || cleanInput.includes('store') || cleanInput.includes('change')) {
      const activeBusinessesCount = await this.prisma.business.count({
        where: { status: 'ACTIVE' },
      });
      if (activeBusinessesCount > 1) {
        await this.sessionService.updateStep(sessionId, 'SELECT_STORE');
        await this.sessionService.updateSessionData(sessionId, {
          selectedCategoryId: undefined,
          selectedProductId: undefined,
          lastProductList: [],
          lastCategoryList: [],
        });
        return this.promptStoreSelection(sessionId);
      }
    }

    const activeBusinessesCount = await this.prisma.business.count({
      where: { status: 'ACTIVE' },
    });
    const welcome = await this.getWelcomeMessage(businessId);
    const validOptionsText = activeBusinessesCount > 1 ? '1, 2, 3, 4, or 5' : '1, 2, 3, or 4';
    return {
      text: `Invalid option. Please reply with ${validOptionsText}.\n\n` + welcome.text,
      payload: welcome.payload
    };
  }

  // --- BROWSE CATEGORIES STEP ---
  private async handleBrowseCategoriesStep(
    sessionId: string,
    businessId: string,
    sessionData: SessionData,
    input: string,
  ): Promise<BotResponse> {
    if (input.toLowerCase() === 'b') {
      await this.sessionService.updateStep(sessionId, 'WELCOME');
      return this.getWelcomeMessage(businessId);
    }

    const cleanInput = input.trim().toLowerCase();
    let index = parseInt(cleanInput) - 1;
    const catIds = sessionData.lastCategoryList || [];
 
    if (isNaN(index) || index < 0 || index >= catIds.length) {
      const categories = await this.prisma.category.findMany({
        where: { id: { in: catIds } },
      });
      const matchedCat = categories.find(
        (cat) => cat.name.toLowerCase() === cleanInput || cleanInput.includes(cat.name.toLowerCase())
      );
      if (matchedCat) {
        index = catIds.indexOf(matchedCat.id);
      }
    }
 
    if (isNaN(index) || index < 0 || index >= catIds.length) {
      return {
        text: `Invalid category number. Please select between 1 and ${catIds.length}, or type *B* to go back.`,
        payload: {
          type: 'pills',
          options: [{ id: 'B', title: 'Back' }]
        }
      };
    }
 
    const categoryId = catIds[index];
    const category = await this.prisma.category.findUnique({ where: { id: categoryId } });

    // List products in category
    const products = await this.prisma.product.findMany({
      where: { businessId, status: 'ACTIVE' },
      orderBy: { name: 'asc' },
    });

    // Link products to categories by matching category name with product name/description in memory
    const categoryName = category?.name.toLowerCase() || '';
    const filteredProducts = products.filter((prod) => {
      if (!categoryName) return true;
      const name = prod.name.toLowerCase();
      const desc = (prod.description || '').toLowerCase();
      
      // Match if category name matches product name/desc or matches singular form (e.g., laptops -> laptop)
      const categorySingular = categoryName.endsWith('s') ? categoryName.slice(0, -1) : categoryName;
      const productSingular = name.endsWith('s') ? name.slice(0, -1) : name;

      return name.includes(categoryName) || 
             categoryName.includes(name) || 
             desc.includes(categoryName) ||
             name.includes(categorySingular) ||
             productSingular.includes(categoryName);
    });

    if (filteredProducts.length === 0) {
      return {
        text: `No products found in the "${category?.name || 'Category'}" category. Type *B* to select another category.`,
        payload: {
          type: 'pills',
          options: [{ id: 'B', title: 'Back' }]
        }
      };
    }

    let response = `*Products in ${category?.name || 'Category'}:*\n\n`;
    const prodIds: string[] = [];
    const carouselItems: any[] = [];
    const productsToDisplay = filteredProducts.slice(0, 9);

    productsToDisplay.forEach((prod, index) => {
      response += `${index + 1}. *${prod.name}* - $${prod.price.toFixed(2)}\n`;
      prodIds.push(prod.id);
      carouselItems.push({
        id: String(index + 1),
        name: prod.name,
        description: prod.description || undefined,
        price: prod.price,
        imageUrl: prod.imageUrl || undefined,
        rating: 4.5 + (index % 5) * 0.1
      });
    });
    response += `\nReply with the product number (e.g. 1) to view details, or type *B* to go back.`;

    await this.sessionService.updateStep(sessionId, 'BROWSE_PRODUCTS');
    await this.sessionService.updateSessionData(sessionId, {
      selectedCategoryId: categoryId,
      lastProductList: prodIds,
    });
    return {
      text: response,
      payload: {
        type: 'product_carousel',
        products: carouselItems
      }
    };
  }

  // --- BROWSE PRODUCTS STEP ---
  private async handleBrowseProductsStep(
    sessionId: string,
    businessId: string,
    sessionData: SessionData,
    input: string,
  ): Promise<BotResponse> {
    if (input.toLowerCase() === 'b') {
      // Go back to categories
      const categories = await this.productsService.listCategories(businessId);
      let response = `*Select a category to browse:*\n\n`;
      const catIds: string[] = [];
      const pills: Array<{ id: string; title: string }> = [];
      const categoriesToDisplay = categories.slice(0, 9);
      categoriesToDisplay.forEach((cat, index) => {
        response += `${index + 1}. ${cat.name}\n`;
        catIds.push(cat.id);
        pills.push({ id: String(index + 1), title: cat.name });
      });
      response += `\nReply with the category number (e.g. 1) or type *B* to go back.`;
      pills.push({ id: 'B', title: 'Back to Menu' });

      await this.sessionService.updateStep(sessionId, 'BROWSE_CATEGORIES');
      await this.sessionService.updateSessionData(sessionId, { lastCategoryList: catIds });
      return {
        text: response,
        payload: {
          type: 'pills',
          options: pills
        }
      };
    }

    const cleanInput = input.trim().toLowerCase();
    let index = parseInt(cleanInput) - 1;
    const prodIds = sessionData.lastProductList || [];
 
    if (isNaN(index) || index < 0 || index >= prodIds.length) {
      const products = await this.prisma.product.findMany({
        where: { id: { in: prodIds } },
      });
      const matchedProd = products.find(
        (prod) => prod.name.toLowerCase() === cleanInput || cleanInput.includes(prod.name.toLowerCase())
      );
      if (matchedProd) {
        index = prodIds.indexOf(matchedProd.id);
      }
    }
 
    if (isNaN(index) || index < 0 || index >= prodIds.length) {
      return {
        text: `Invalid product number. Please select between 1 and ${prodIds.length}, or type *B* to go back.`,
        payload: {
          type: 'pills',
          options: [{ id: 'B', title: 'Back' }]
        }
      };
    }
 
    const productId = prodIds[index];
    const product = await this.prisma.product.findUnique({
      where: { id: productId },
      include: { variants: true },
    });

    if (!product) {
      return {
        text: `Product no longer available. Type *B* to go back.`,
        payload: {
          type: 'pills',
          options: [{ id: 'B', title: 'Back' }]
        }
      };
    }

    let response = `*${product.name}*\n\n` +
      `Price: *$${product.price.toFixed(2)}*\n` +
      `Stock: ${product.stockQuantity !== null ? product.stockQuantity : 'Available'}\n` +
      `SKU: ${product.sku || 'N/A'}\n\n` +
      `${product.description || 'No description provided.'}\n\n`;

    if (product.variants.length > 0) {
      response += `*Available Options:*\n`;
      product.variants.forEach((v) => {
        response += `- ${v.name} ($${v.price.toFixed(2)})\n`;
      });
      response += `\n_(Note: Standard option will be added)_ \n\n`;
    }

    response += `*To add to cart, reply with the quantity (e.g. 1, 2) or type B to go back.*`;

    await this.sessionService.updateStep(sessionId, 'PRODUCT_DETAILS');
    await this.sessionService.updateSessionData(sessionId, { selectedProductId: productId });
    return {
      text: response,
      payload: {
        type: 'product_detail',
        product: {
          name: product.name,
          description: product.description || undefined,
          price: product.price,
          imageUrl: product.imageUrl || undefined
        },
        buttons: [
          { id: '1', title: 'Add to Cart', icon: 'shopping-cart.svg' },
          { id: 'B', title: 'Back', icon: 'icons8-box.svg' }
        ]
      }
    };
  }

  // --- PRODUCT DETAILS STEP ---
  private async handleProductDetailsStep(
    sessionId: string,
    businessId: string,
    whatsappNumber: string,
    sessionData: SessionData,
    input: string,
  ): Promise<BotResponse> {
    if (input.toLowerCase() === 'b') {
      // Go back to the product list
      await this.sessionService.updateStep(sessionId, 'BROWSE_PRODUCTS');
      return {
        text: `Please reply with the product number to view details, or type *B* to go back.`,
        payload: {
          type: 'pills',
          options: [{ id: 'B', title: 'Back' }]
        }
      };
    }

    const numMatch = input.match(/\d+/);
    const quantity = numMatch ? parseInt(numMatch[0], 10) : NaN;
    if (isNaN(quantity) || quantity <= 0) {
      return {
        text: `Please enter a valid quantity (positive number, e.g. 1, 2) or type *B* to go back.`,
        payload: {
          type: 'pills',
          options: [{ id: 'B', title: 'Back' }]
        }
      };
    }
 
    const productId = sessionData.selectedProductId;
    if (!productId) {
      await this.sessionService.updateStep(sessionId, 'WELCOME');
      return this.getWelcomeMessage(businessId);
    }
 
    // Default to main product add. If product has variants, for simplicity of chatbot MVP,
    // we fetch first variant or default to main product.
    const product = await this.prisma.product.findUnique({
      where: { id: productId },
      include: { variants: true },
    });
 
    if (!product) {
      return {
        text: `Product not found. Type *B* to go back.`,
        payload: {
          type: 'pills',
          options: [{ id: 'B', title: 'Back' }]
        }
      };
    }
 
    const variantId = product.variants?.[0]?.id || undefined;
 
    try {
      await this.cartsService.addToCart(businessId, whatsappNumber, productId, quantity, variantId);
    } catch (err: any) {
      return {
        text: `⚠️ *Stock Limit Exceeded*\n\n${err.message}\n\n` +
          `Reply with a smaller quantity, or type *B* to go back.`,
        payload: {
          type: 'pills',
          options: [{ id: 'B', title: 'Back' }]
        }
      };
    }
 
    await this.sessionService.updateStep(sessionId, 'POST_ADD_TO_CART');
    return {
      text: `Added *${product.name}* (Qty: ${quantity}) to your cart!\n\n` +
        `What would you like to do next?\n` +
        `1. View Cart\n` +
        `2. Continue Shopping\n` +
        `3. Add More`,
      payload: {
        type: 'pills',
        options: [
          { id: '1', title: 'View Cart', icon: 'shopping-cart.svg' },
          { id: '2', title: 'Continue Shopping', icon: 'icons8-box.svg' },
          { id: '3', title: 'Add More', icon: 'icons8-list.svg' }
        ]
      }
    };
  }
 
  // --- POST ADD TO CART STEP ---
  private async handlePostAddToCartStep(
    sessionId: string,
    businessId: string,
    whatsappNumber: string,
    sessionData: SessionData,
    input: string,
  ): Promise<BotResponse> {
    const cleanInput = input.trim().toLowerCase();

    if (cleanInput === '1' || cleanInput.includes('view') || cleanInput.includes('checkout') || cleanInput.includes('cart')) {
      return this.printCart(businessId, whatsappNumber);
    }

    if (cleanInput === '2' || cleanInput.includes('continue') || cleanInput.includes('shop') || cleanInput.includes('browse')) {
      await this.sessionService.updateStep(sessionId, 'WELCOME');
      return this.getWelcomeMessage(businessId);
    }

    if (cleanInput === '3' || cleanInput.includes('add') || cleanInput.includes('more')) {
      const productId = sessionData.selectedProductId;
      if (productId) {
        const product = await this.prisma.product.findUnique({
          where: { id: productId },
          include: { variants: true },
        });

        if (product) {
          await this.sessionService.updateStep(sessionId, 'ADD_MORE_QUANTITY');
          const webviewUrl = `${process.env.PUBLIC_URL || 'http://localhost:3001'}/whatsapp/quantity?productId=${productId}&phone=${whatsappNumber}&businessId=${businessId}`;
          return {
            text: `How many more of *${product.name}* would you like to add?\n\n` +
              `Tap the "Select Quantity" button below to select/type the quantity using your keyboard, or reply with a number (e.g., 1, 2, 5) or *B* to go back.`,
            payload: {
              type: 'cta_url',
              url: webviewUrl,
              urlButtonText: 'Select Quantity',
              followUpOptions: [
                { id: 'B', title: 'Back' }
              ]
            }
          };
        }
      }
    }

    return {
      text: `Invalid option. Reply "1" to view cart, "2" to continue shopping, or "3" to add more of this product.`,
      payload: {
        type: 'pills',
        options: [
          { id: '1', title: 'View Cart' },
          { id: '2', title: 'Continue Shopping' },
          { id: '3', title: 'Add More' }
        ]
      }
    };
  }

  // --- ADD MORE QUANTITY STEP ---
  private async handleAddMoreQuantityStep(
    sessionId: string,
    businessId: string,
    whatsappNumber: string,
    sessionData: SessionData,
    input: string,
  ): Promise<BotResponse> {
    const cleanInput = input.trim();

    const productId = sessionData.selectedProductId;
    if (!productId) {
      await this.sessionService.updateStep(sessionId, 'WELCOME');
      return this.getWelcomeMessage(businessId);
    }

    const product = await this.prisma.product.findUnique({
      where: { id: productId },
      include: { variants: true },
    });

    if (!product) {
      await this.sessionService.updateStep(sessionId, 'WELCOME');
      return this.getWelcomeMessage(businessId);
    }

    if (cleanInput.toLowerCase() === 'b' || cleanInput.toLowerCase() === 'back') {
      await this.sessionService.updateStep(sessionId, 'POST_ADD_TO_CART');
      return {
        text: `What would you like to do next with *${product.name}*?\n\n` +
          `1. View Cart\n` +
          `2. Continue Shopping\n` +
          `3. Add More`,
        payload: {
          type: 'pills',
          options: [
            { id: '1', title: 'View Cart', icon: 'shopping-cart.svg' },
            { id: '2', title: 'Continue Shopping', icon: 'icons8-box.svg' },
            { id: '3', title: 'Add More', icon: 'icons8-list.svg' }
          ]
        }
      };
    }

    const numMatch = cleanInput.match(/\d+/);
    const quantity = numMatch ? parseInt(numMatch[0], 10) : NaN;
    if (isNaN(quantity) || quantity <= 0) {
      const webviewUrl = `${process.env.PUBLIC_URL || 'http://localhost:3001'}/whatsapp/quantity?productId=${productId}&phone=${whatsappNumber}&businessId=${businessId}`;
      return {
        text: `Please enter a valid quantity (positive number, e.g., 1, 2, 5), tap "Select Quantity" below to select/type using your keyboard, or type *B* to go back.`,
        payload: {
          type: 'cta_url',
          url: webviewUrl,
          urlButtonText: 'Select Quantity',
          followUpOptions: [
            { id: 'B', title: 'Back' }
          ]
        }
      };
    }

    const variantId = product.variants?.[0]?.id || undefined;
    try {
      await this.cartsService.addToCart(businessId, whatsappNumber, productId, quantity, variantId);
    } catch (err: any) {
      const webviewUrl = `${process.env.PUBLIC_URL || 'http://localhost:3001'}/whatsapp/quantity?productId=${productId}&phone=${whatsappNumber}&businessId=${businessId}`;
      return {
        text: `⚠️ *Stock Limit Exceeded*\n\n${err.message}\n\n` +
          `Reply with a smaller quantity, tap "Select Quantity" below to select/type using your keyboard, or type *B* to go back.`,
        payload: {
          type: 'cta_url',
          url: webviewUrl,
          urlButtonText: 'Select Quantity',
          followUpOptions: [
            { id: 'B', title: 'Back' }
          ]
        }
      };
    }

    // Get total quantity of this product in cart now
    const cart = await this.cartsService.getOrCreateCart(businessId, whatsappNumber);
    const cartItem = cart.items.find(item => item.productId === productId);
    const totalQty = cartItem ? cartItem.quantity : quantity;

    await this.sessionService.updateStep(sessionId, 'POST_ADD_TO_CART');

    return {
      text: `Added *${quantity}* more *${product.name}* to your cart! (Total in cart: *${totalQty}*)\n\n` +
        `What would you like to do next?\n` +
        `1. View Cart\n` +
        `2. Continue Shopping\n` +
        `3. Add More`,
      payload: {
        type: 'pills',
        options: [
          { id: '1', title: 'View Cart' },
          { id: '2', title: 'Continue Shopping' },
          { id: '3', title: 'Add More' }
        ]
      }
    };
  }
 
  // --- SEARCH PRODUCTS STEP ---
  private async handleSearchProductsStep(
    sessionId: string,
    businessId: string,
    input: string,
  ): Promise<BotResponse> {
    if (input.toLowerCase() === 'b') {
      await this.sessionService.updateStep(sessionId, 'WELCOME');
      return this.getWelcomeMessage(businessId);
    }
 
    const products = await this.productsService.listProducts(businessId, input);
 
    if (products.length === 0) {
      return {
        text: `No products found matching "${input}".\n\nReply with a different search term, or type *B* to go back to the main menu.`,
        payload: {
          type: 'pills',
          options: [{ id: 'B', title: 'Back to Menu' }]
        }
      };
    }
 
    let response = `*Search Results for "${input}":*\n\n`;
    const prodIds: string[] = [];
    const carouselItems: any[] = [];
    const productsToDisplay = products.slice(0, 9);
 
    productsToDisplay.forEach((prod, index) => {
      response += `${index + 1}. *${prod.name}* - $${prod.price.toFixed(2)}\n`;
      prodIds.push(prod.id);
      carouselItems.push({
        id: String(index + 1),
        name: prod.name,
        description: prod.description || undefined,
        price: prod.price,
        imageUrl: prod.imageUrl || undefined,
        rating: 4.5 + (index % 5) * 0.1
      });
    });
    response += `\nReply with the product number (e.g. 1) to view details, or type *B* to go back.`;
 
    await this.sessionService.updateStep(sessionId, 'BROWSE_PRODUCTS');
    await this.sessionService.updateSessionData(sessionId, { lastProductList: prodIds });
    return {
      text: response,
      payload: {
        type: 'product_carousel',
        products: carouselItems
      }
    };
  }
 
  // --- CART STEP ---
  private async handleCartStep(
    sessionId: string,
    businessId: string,
    whatsappNumber: string,
    input: string,
  ): Promise<BotResponse> {
    const cleanInput = input.trim();

    // Check for quantity adjustments (e.g. +1, -2)
    const qtyChangeMatch = cleanInput.match(/^([+-])(\d+)$/);
    if (qtyChangeMatch) {
      const operation = qtyChangeMatch[1]; // "+" or "-"
      const index = parseInt(qtyChangeMatch[2], 10) - 1; // Convert 1-based index to 0-based

      const cart = await this.cartsService.getOrCreateCart(businessId, whatsappNumber);

      if (index >= 0 && index < cart.items.length) {
        const item = cart.items[index];
        const newQty = operation === '+' ? item.quantity + 1 : item.quantity - 1;

        await this.cartsService.updateItemQuantity(cart.id, item.id, newQty);

        // Return updated cart view
        return this.printCart(businessId, whatsappNumber);
      } else {
        return {
          text: `Invalid item number. Please verify the number of the item you want to edit and try again.\n\n` +
            `Example: *+1* to add to item 1, or *-1* to remove.`,
          payload: {
            type: 'pills',
            options: [
              { id: '1', title: 'Checkout' },
              { id: '2', title: 'Clear Cart' },
              { id: 'B', title: 'Back' }
            ]
          }
        };
      }
    }

    if (cleanInput === '1' || cleanInput.includes('checkout') || cleanInput.includes('proceed')) {
      // Start checkout
      await this.sessionService.updateStep(sessionId, 'CHECKOUT_NAME');
      return {
        text: `*Checkout*\n\nPlease reply with your *Full Name* to begin:`,
        payload: {
          type: 'pills',
          options: [{ id: 'B', title: 'Back' }]
        }
      };
    }

    if (cleanInput === '2' || cleanInput.includes('clear')) {
      const cart = await this.cartsService.getOrCreateCart(businessId, whatsappNumber);
      await this.cartsService.clearCart(cart.id);
      return {
        text: `Cart cleared!\n\nReply *B* to return to the main menu.`,
        payload: {
          type: 'pills',
          options: [{ id: 'B', title: 'Back to Menu' }]
        }
      };
    }

    return {
      text: `Invalid option. Reply 1 to Checkout, 2 to Clear Cart, or B to go back.\n\n` +
        `💡 *Tip*: You can adjust item quantities by replying with *+<number>* or *-<number>* (e.g. *+1* adds one more Wireless Mouse, *-2* removes one Bluetooth Speaker).`,
      payload: {
        type: 'pills',
        options: [
          { id: '1', title: 'Checkout', icon: 'icons8-cart.svg' },
          { id: '2', title: 'Clear Cart', icon: 'icons8-list.svg' },
          { id: 'B', title: 'Back', icon: 'icons8-box.svg' }
        ]
      }
    };
  }
 
  // --- CHECKOUT NAME STEP ---
  private async handleCheckoutNameStep(
    sessionId: string,
    businessId: string,
    sessionData: SessionData,
    input: string,
  ): Promise<BotResponse> {
    if (input.toLowerCase() === 'b' || input.toLowerCase() === 'cancel') {
      await this.sessionService.clearSession(sessionId);
      return this.getWelcomeMessage(businessId);
    }
 
    if (!input || input.length < 2) {
      return {
        text: `Please enter a valid name (at least 2 letters):`,
        payload: {
          type: 'pills',
          options: [{ id: 'B', title: 'Cancel' }]
        }
      };
    }
 
    await this.sessionService.updateSessionData(sessionId, { customerName: input });
    await this.sessionService.updateStep(sessionId, 'CHECKOUT_DELIVERY');
 
    return {
      text: `Hi *${input}*!\n\nHow would you like to receive your order?\n` +
        `1. Home Delivery\n` +
        `2. Store Pickup`,
      payload: {
        type: 'pills',
        options: [
          { id: '1', title: 'Home Delivery', icon: 'checkout.svg' },
          { id: '2', title: 'Store Pickup', icon: 'icons8-settings.svg' }
        ]
      }
    };
  }

  // --- CHECKOUT DELIVERY STEP ---
  private async handleCheckoutDeliveryStep(
    sessionId: string,
    sessionData: SessionData,
    input: string,
  ): Promise<BotResponse> {
    const cleanInput = input.trim().toLowerCase();
    if (cleanInput === '1' || cleanInput.includes('delivery')) {
      await this.sessionService.updateSessionData(sessionId, { deliveryMethod: 'delivery' });
      await this.sessionService.updateStep(sessionId, 'CHECKOUT_ADDRESS');
      return {
        text: `*Delivery Address*\n\nPlease reply with your *Physical Address* for delivery, or simply *Share your Location* directly:`,
        payload: {
          type: 'pills',
          options: [{ id: 'B', title: 'Back' }]
        }
      };
    }

    if (cleanInput === '2' || cleanInput.includes('pickup')) {
      await this.sessionService.updateSessionData(sessionId, {
        deliveryMethod: 'pickup',
        deliveryAddress: 'Store Pickup',
      });
      await this.sessionService.updateStep(sessionId, 'CHECKOUT_CONFIRM');
      return this.printOrderConfirmationSummary(sessionData.customerName || 'Customer', 'Store Pickup', 'pickup');
    }

    return {
      text: `Invalid option. Reply 1 for Home Delivery or 2 for Store Pickup.`,
      payload: {
        type: 'pills',
        options: [
          { id: '1', title: 'Home Delivery', icon: 'checkout.svg' },
          { id: '2', title: 'Store Pickup', icon: 'icons8-settings.svg' }
        ]
      }
    };
  }

  // --- CHECKOUT ADDRESS STEP ---
  private async handleCheckoutAddressStep(
    sessionId: string,
    businessId: string,
    whatsappNumber: string,
    sessionData: SessionData,
    input: string,
  ): Promise<BotResponse> {
    if (input.toLowerCase() === 'b') {
      await this.sessionService.updateStep(sessionId, 'CHECKOUT_DELIVERY');
      return {
        text: `How would you like to receive your order?\n` +
          `1. Home Delivery\n` +
          `2. Store Pickup`,
        payload: {
          type: 'pills',
          options: [
            { id: '1', title: 'Home Delivery', icon: 'checkout.svg' },
            { id: '2', title: 'Store Pickup', icon: 'icons8-settings.svg' }
          ]
        }
      };
    }

    if (input.startsWith('LOCATION_SHARED:')) {
      const parts = input.replace('LOCATION_SHARED:', '').split(',');
      const latPart = parts.find(p => p.startsWith('lat='));
      const lngPart = parts.find(p => p.startsWith('lng='));
      const namePart = parts.find(p => p.startsWith('name='));
      const addrPart = parts.find(p => p.startsWith('address='));

      const lat = latPart ? parseFloat(latPart.split('=')[1]) : null;
      const lng = lngPart ? parseFloat(lngPart.split('=')[1]) : null;
      const name = namePart ? namePart.split('=')[1] : '';
      const address = addrPart ? addrPart.split('=')[1] : '';

      if (lat !== null && lng !== null && !isNaN(lat) && !isNaN(lng)) {
        const addressLabel = address || name || `Shared Location (${lat.toFixed(4)}, ${lng.toFixed(4)})`;

        await this.sessionService.updateSessionData(sessionId, {
          deliveryAddress: addressLabel,
          deliveryLat: lat,
          deliveryLng: lng
        });

        // Update active orders in DB if any
        await this.prisma.order.updateMany({
          where: {
            customerPhone: { contains: whatsappNumber.replace(/[^0-9]/g, '') },
            status: { in: ['PENDING', 'PREPARING', 'DISPATCHED', 'IN_TRANSIT'] },
          },
          data: { deliveryLat: lat, deliveryLng: lng, deliveryAddress: addressLabel },
        });

        await this.sessionService.updateStep(sessionId, 'CHECKOUT_CONFIRM');

        const cart = await this.cartsService.getOrCreateCart(businessId, whatsappNumber);
        return this.printOrderConfirmationSummary(
          sessionData.customerName || 'Customer',
          addressLabel,
          'delivery',
          cart.totalAmount,
        );
      }
    }

    if (!input || input.length < 5) {
      return {
        text: `Please enter a valid physical address, or share your location:`,
        payload: {
          type: 'pills',
          options: [{ id: 'B', title: 'Back' }]
        }
      };
    }

    // Resolve Google Maps link if customer pasted a map URL (e.g., https://maps.app.goo.gl/...)
    let resolvedLat: number | null = null;
    let resolvedLng: number | null = null;
    if (input.includes('maps') || input.includes('goo.gl')) {
      const coords = await this.resolveGoogleMapsCoordinates(input);
      if (coords.lat !== null && coords.lng !== null) {
        resolvedLat = coords.lat;
        resolvedLng = coords.lng;
      }
    }

    await this.sessionService.updateSessionData(sessionId, {
      deliveryAddress: input,
      deliveryLat: resolvedLat ?? undefined,
      deliveryLng: resolvedLng ?? undefined,
    });

    if (resolvedLat !== null && resolvedLng !== null) {
      await this.prisma.order.updateMany({
        where: {
          customerPhone: { contains: whatsappNumber.replace(/[^0-9]/g, '') },
          status: { in: ['PENDING', 'PREPARING', 'DISPATCHED', 'IN_TRANSIT'] },
        },
        data: { deliveryLat: resolvedLat, deliveryLng: resolvedLng },
      });
    }

    await this.sessionService.updateStep(sessionId, 'CHECKOUT_CONFIRM');

    // Get cart total to display
    const cart = await this.cartsService.getOrCreateCart(businessId, whatsappNumber);

    return this.printOrderConfirmationSummary(
      sessionData.customerName || 'Customer',
      input,
      'delivery',
      cart.totalAmount,
    );
  }

  private printOrderConfirmationSummary(
    name: string,
    address: string,
    method: string,
    total?: number,
  ): BotResponse {
    const text = `*Confirm Your Order*\n\n` +
      `*Name:* ${name}\n` +
      `*Method:* ${method === 'delivery' ? 'Home Delivery' : 'Store Pickup'}\n` +
      `*Address:* ${address}\n` +
      (total ? `*Total Amount:* $${total.toFixed(2)}\n\n` : `\n`) +
      `Ready to place your order? Reply:\n` +
      `1. Confirm & Pay\n` +
      `2. Cancel Order`;

    return {
      text,
      payload: {
        type: 'pills',
        options: [
          { id: '1', title: 'Confirm & Pay', icon: 'checkout.svg' },
          { id: '2', title: 'Cancel Order', icon: 'icons8-list.svg' }
        ]
      }
    };
  }

  // --- CHECKOUT CONFIRM STEP ---
  private async handleCheckoutConfirmStep(
    sessionId: string,
    businessId: string,
    whatsappNumber: string,
    sessionData: SessionData,
    input: string,
  ): Promise<BotResponse> {
    const cleanInput = input.trim().toLowerCase();
    if (cleanInput === '1' || cleanInput.includes('confirm') || cleanInput.includes('pay')) {
      try {
        const result = await this.ordersService.createOrderFromCart(
          businessId,
          whatsappNumber,
          sessionData.customerName || 'WhatsApp Customer',
          sessionData.deliveryMethod || 'pickup',
          sessionData.deliveryAddress,
          sessionData.deliveryLat,
          sessionData.deliveryLng,
        );

        // Transition to EcoCash number collection step
        await this.sessionService.updateStep(sessionId, 'CHECKOUT_ECOCASH');
        await this.sessionService.updateSessionData(sessionId, {
          pendingOrderId: result.orderId,
        });

        return {
          text: `*Order Placed! Payment Required*\n\n` +
            `Order: *${result.orderNumber}*\n` +
            `Total: *${result.currency} $${result.totalAmount.toFixed(2)}*\n\n` +
            `To pay via EcoCash, please send your EcoCash number:\n` +
            `  Format: *26377XXXXXXX* or *077XXXXXXX*\n\n` +
            `_You can also click the button below to use your current WhatsApp number._`,
          payload: {
            type: 'pills',
            options: [
              { id: whatsappNumber, title: `Use ${whatsappNumber}`, icon: 'icons8-user.svg' },
              { id: 'cancel', title: 'Cancel Order', icon: 'icons8-list.svg' }
            ]
          },
        };

      } catch (err: any) {
        this.logger.error(`Error confirming checkout: ${err.message}`);
        await this.sessionService.clearSession(sessionId);
        return {
          text: `We could not complete your order at the moment. Please try again or request assistance from our sales team.`,
          payload: {
            type: 'pills',
            options: [
              { id: 'menu', title: 'Main Menu' },
              { id: '4', title: 'Talk to Support' }
            ]
          }
        };
      }
    }

    if (cleanInput === '2' || cleanInput.includes('cancel')) {
      await this.sessionService.clearSession(sessionId);
      const welcomeMsg = await this.getWelcomeMessage(businessId);
      return {
        text: `Order cancelled.\n\n` + welcomeMsg.text,
        payload: welcomeMsg.payload
      };
    }

    return {
      text: `Invalid option. Reply 1 to Confirm & Pay, or 2 to Cancel Order.`,
      payload: {
        type: 'pills',
        options: [
          { id: '1', title: 'Confirm & Pay' },
          { id: '2', title: 'Cancel Order' }
        ]
      }
    };
  }

  // --- CHECKOUT ECOCASH STEP ---
  private async handleCheckoutEcoCashStep(
    sessionId: string,
    businessId: string,
    whatsappNumber: string,
    sessionData: SessionData,
    input: string,
  ): Promise<BotResponse> {
    const cleanInput = input.trim().toLowerCase();

    if (cleanInput === 'cancel' || cleanInput === 'cancel order' || cleanInput.includes('cancel')) {
      const orderId = sessionData.pendingOrderId;
      if (orderId) {
        try {
          await this.ordersService.updateOrderStatus(businessId, orderId, 'CANCELLED');
        } catch (err: any) {
          this.logger.error(`Failed to cancel order ${orderId} in database: ${err.message}`);
        }
      }
      await this.sessionService.clearSession(sessionId);
      const welcomeMsg = await this.getWelcomeMessage(businessId);
      return {
        text: `Your order has been cancelled. ❌\n\n` + welcomeMsg.text,
        payload: welcomeMsg.payload,
      };
    }

    const raw = input.trim().replace(/\s+/g, '');

    // Normalise: accept 07XXXXXXXX → 263 + rest
    let ecocashNumber = raw;
    if (/^0[0-9]{9}$/.test(raw)) {
      ecocashNumber = '263' + raw.substring(1);
    }

    if (!/^263[0-9]{9}$/.test(ecocashNumber)) {
      return {
        text: `Invalid EcoCash number format. Please try again.\n\n` +
          `Valid formats:\n  *26377XXXXXXX* (international)\n  *077XXXXXXX* (local)\n\n` +
          `Please send your EcoCash number:`,
        payload: {
          type: 'pills',
          options: [
            { id: whatsappNumber, title: `Use ${whatsappNumber}` },
            { id: 'cancel', title: 'Cancel Order' }
          ]
        },
      };
    }

    const orderId = sessionData.pendingOrderId;
    if (!orderId) {
      await this.sessionService.clearSession(sessionId);
      return {
        text: `Your session has expired. Please start over.`,
        payload: { type: 'pills', options: [{ id: 'menu', title: 'Main Menu' }] },
      };
    }

    try {
      const { paymentReference, amount, currency } = await this.ordersService.initiateSeamlessPayment(
        businessId,
        orderId,
        whatsappNumber,
        ecocashNumber,
      );

      // Transition to AWAITING_PAYMENT
      await this.sessionService.updateStep(sessionId, 'AWAITING_PAYMENT');
      await this.sessionService.updateSessionData(sessionId, {
        pendingPaymentRef: paymentReference,
        ecocashNumber,
        amount,
        currency,
      });

      return {
        text: `*EcoCash Payment Initiated!*\n\n` +
          `A payment request of *${currency} $${amount.toFixed(2)}* has been sent to *${ecocashNumber}*.\n` +
          `Ref: *${paymentReference}*\n\n` +
          `Please check your EcoCash menu and enter your PIN to approve.\n\n` +
          `_You will receive a WhatsApp confirmation once payment is processed._`,
        payload: {
          type: 'pills',
          options: [
            { id: 'cancel', title: 'Cancel Payment', icon: 'icons8-list.svg' },
            { id: 'menu', title: 'Main Menu', icon: 'icons8-box.svg' },
          ],
        },
      };
    } catch (err: any) {
      this.logger.error(`EcoCash payment initiation failed: ${err.message}`);
      await this.sessionService.clearSession(sessionId);
      return {
        text: `We could not initiate your EcoCash payment at the moment.\n` +
          `Error: ${err.message}\n\n` +
          `Please try again or contact support.`,
        payload: {
          type: 'pills',
          options: [
            { id: 'menu', title: 'Main Menu', icon: 'icons8-box.svg' },
            { id: '4', title: 'Talk to Support', icon: 'icons8-user.svg' },
          ],
        },
      };
    }
  }

  // --- AWAITING PAYMENT STEP ---
  private async handleAwaitingPaymentStep(
    sessionId: string,
    businessId: string,
    whatsappNumber: string,
    sessionData: SessionData,
    input: string,
  ): Promise<BotResponse> {
    const cleanInput = input.trim().toLowerCase();

    if (cleanInput === 'cancel' || cleanInput === 'cancel payment' || cleanInput.includes('cancel')) {
      const pendingPayment = await this.prisma.payment.findFirst({
        where: {
          orderId: sessionData.pendingOrderId,
          status: 'PENDING',
        },
      });

      if (pendingPayment) {
        await this.prisma.payment.update({
          where: { id: pendingPayment.id },
          data: { status: 'FAILED' },
        });

        await this.prisma.order.update({
          where: { id: pendingPayment.orderId },
          data: { status: 'PENDING', paymentStatus: 'FAILED' },
        });
      }

      await this.sessionService.clearSession(sessionId);

      const welcomeMsg = await this.getWelcomeMessage(businessId);
      return {
        text: `Your pending EcoCash payment has been cancelled.\n\n` + welcomeMsg.text,
        payload: welcomeMsg.payload,
      };
    }

    const currency = sessionData.currency || 'USD';
    const amount = sessionData.amount !== undefined ? parseFloat(String(sessionData.amount)).toFixed(2) : '0.00';
    return {
      text: `Your EcoCash payment of *${currency} $${amount}* is currently pending confirmation.\n\n` +
        `Please check your phone for the EcoCash PIN prompt and enter your PIN to approve.\n\n` +
        `_If you did not receive the prompt or wish to cancel, reply *cancel* to return to the main menu._`,
      payload: {
        type: 'pills',
        options: [
          { id: 'cancel', title: 'Cancel Payment', icon: 'icons8-list.svg' },
          { id: 'menu', title: 'Main Menu', icon: 'icons8-box.svg' },
        ],
      },
    };
  }

  // --- PRINT CART HELP ---
  private async printCart(businessId: string, whatsappNumber: string): Promise<BotResponse> {
    const cart = await this.cartsService.getOrCreateCart(businessId, whatsappNumber);
    const session = await this.prisma.session.findFirst({ where: { businessId, whatsappNumber } });

    if (cart.items.length === 0) {
      if (session) await this.sessionService.updateStep(session.id, 'WELCOME');
      return {
        text: `Your cart is empty!\n\nType *1* to browse products, or *menu* to return.`,
        payload: {
          type: 'pills',
          options: [{ id: '1', title: 'Browse Products' }]
        }
      };
    }

    let response = `*Your Shopping Cart:*\n\n`;
    cart.items.forEach((item, index) => {
      const name = item.variant ? `${item.product.name} (${item.variant.name})` : item.product.name;
      response += `${index + 1}. *${name}*\n` +
        `   Qty: ${item.quantity} x $${item.unitPrice.toFixed(2)} = *$${item.lineTotal.toFixed(2)}*\n`;
    });

    response += `\n*Total Amount: $${cart.totalAmount.toFixed(2)}*\n\n` +
      `💡 *Tip*: Reply *+<number>* to add one, or *-<number>* to remove one (e.g. *+1* to add to item 1, *-2* to remove from item 2).\n\n` +
      `Reply with a number:\n` +
      `1. Checkout\n` +
      `2. Clear Cart\n\n` +
      `Type *B* to continue shopping.`;

    if (session) await this.sessionService.updateStep(session.id, 'CART');
    return {
      text: response,
      payload: {
        type: 'pills',
        options: [
          { id: '1', title: 'Checkout' },
          { id: '2', title: 'Clear Cart' },
          { id: 'B', title: 'Continue Shopping' }
        ]
      }
    };
  }

  // --- SUPPORT STEP ---
  private async handleSupportStep(
    sessionId: string,
    businessId: string,
    input: string,
  ): Promise<BotResponse> {
    const cleanInput = input.trim().toLowerCase();

    if (cleanInput === '3' || cleanInput.includes('exit')) {
      await this.sessionService.clearSession(sessionId);
      return this.getWelcomeMessage(businessId);
    }

    if (cleanInput === '1' || cleanInput.includes('call')) {
      return {
        text: `*Call Quatrohaus Support*\n\nYou can call our support team directly at:\n\n+2637776015100`,
        payload: {
          type: 'pills',
          options: [
            { id: '2', title: 'Message Quatrohaus' },
            { id: '3', title: 'Exit Support' }
          ]
        }
      };
    }

    if (cleanInput === '2' || cleanInput.includes('message') || cleanInput.includes('wa.me')) {
      return {
        text: `*Message Quatrohaus Support*\n\nYou can chat with us on WhatsApp here:\n\nhttps://wa.me/2637776015100`,
        payload: {
          type: 'pills',
          options: [
            { id: '1', title: 'Call Quatrohaus' },
            { id: '3', title: 'Exit Support' }
          ]
        }
      };
    }

    // Default fallback if they enter something else in the support flow
    return {
      text: `*Customer Support*\n\nHow would you like to contact Quatrohaus Support?\n\n1. Call Quatrohaus\n2. Message Quatrohaus\n3. Exit Support`,
      payload: {
        type: 'pills',
        options: [
          { id: '1', title: 'Call Quatrohaus' },
          { id: '2', title: 'Message Quatrohaus' },
          { id: '3', title: 'Exit Support' }
        ]
      }
    };
  }

  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 in WhatsApp bot: ${err}`);
    }

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