import prisma from "../../db.server";
import { REGISTERED_AI_TOOLS, AIToolDefinition } from "./tools";
import { canUseFeature } from "../billing-plans";
import { BillingService } from "../../services/billing.server";
import { SubscriptionService } from "../../services/subscription.server";
import { searchProductsService } from "../../services/product.server";
import { getCustomerOrdersService, cancelOrderService, trackOrderSecurelyService } from "../../services/order.server";
import { createReturnService } from "../../services/return.server";
import {
  createCartService,
  applyDiscountService,
  getAvailableDiscountCodesService,
  validateDiscountCodeService,
  calculateShippingRatesService,
} from "../../services/cart.server";
import { searchArticlesService, getArticleDetailsService } from "../../services/article.server";
import { getTenantByDomain, assertMultiStoreSafety } from "../security/tenant-context";
import { logger } from "../security/logger";
import { GeminiProvider } from "../ai/gemini-provider";
import { DynamicPromptBuilder } from "../ai/dynamic-prompt-builder";
import { formatCurrency } from "../currency";
import { parseWidgetSettings } from "../../services/widget-settings.server";
import { StoreProfileService } from "../../services/store-profile.server";
import { CatalogRetrievalService } from "../../services/catalog-retrieval.server";
import { PolicyRetrievalService } from "../../services/policy-retrieval.server";
import { ThemeContextService } from "../../services/theme-context.server";
import { PlanCapabilityService } from "../../services/plan-capability.server";
import { extractIntentAndFilters } from "../ai/intent-extractor";

const SENSITIVE_FIELDS = new Set([
  "password",
  "token",
  "accessToken",
  "customerAccessToken",
  "apiKey",
  "authorization",
  "creditCard",
  "cardNumber",
  "cvv",
  "pin",
  "secret",
]);

export function redactSensitive(value: unknown): unknown {
  if (!value || typeof value !== "object") return value;
  if (Array.isArray(value)) return value.map(redactSensitive);
  return Object.fromEntries(
    Object.entries(value as Record<string, unknown>).map(([k, v]) => [
      k,
      SENSITIVE_FIELDS.has(k) ? "[REDACTED]" : redactSensitive(v),
    ])
  );
}

// Server-side confirmation state for destructive actions (TTL: 10 minutes)
const PENDING_CONFIRMATIONS = new Map<
  string,
  { action: "cancel_order" | "create_return"; orderId: string; expiresAt: number; reason?: string }
>();

export const PLAN_TOOL_PERMISSIONS: Record<string, Set<string>> = {
  UNKNOWN: new Set(["search_products", "get_product_details", "search_blog_posts", "get_article_details", "get_store_contact_info"]),
  FREE: new Set(["search_products", "get_product_details", "search_blog_posts", "get_article_details", "get_store_contact_info"]),
  ONE_TIME: new Set(["search_products", "get_product_details", "search_blog_posts", "get_article_details", "get_store_contact_info"]),
  STARTER: new Set([
    "search_products",
    "get_product_details",
    "search_blog_posts",
    "get_article_details",
    "get_store_contact_info",
    "create_cart",
    "add_to_cart",
    "update_cart",
    "update_cart_quantity",
    "calculate_shipping_rates",
    "get_available_discount_codes",
    "validate_discount_code",
    "apply_discount_code",
    "create_checkout",
  ]),
  GROWTH: new Set([
    "search_products",
    "get_product_details",
    "search_blog_posts",
    "get_article_details",
    "get_store_contact_info",
    "create_cart",
    "add_to_cart",
    "update_cart",
    "update_cart_quantity",
    "calculate_shipping_rates",
    "get_available_discount_codes",
    "validate_discount_code",
    "apply_discount_code",
    "create_checkout",
    "track_order",
    "get_customer_orders",
    "create_return",
    "cancel_order",
    "handoff_to_human",
    "search_knowledge_base",
  ]),
  PRO: new Set([
    "search_products",
    "get_product_details",
    "search_blog_posts",
    "get_article_details",
    "get_store_contact_info",
    "create_cart",
    "add_to_cart",
    "update_cart",
    "update_cart_quantity",
    "calculate_shipping_rates",
    "get_available_discount_codes",
    "validate_discount_code",
    "apply_discount_code",
    "create_checkout",
    "track_order",
    "get_customer_orders",
    "create_return",
    "cancel_order",
    "handoff_to_human",
    "search_knowledge_base",
  ]),
};

export interface AgentRunParams {
  shopDomain: string;
  sessionId: string;
  userMessage: string;
  customerAccessToken?: string;
  model?: string;
}

export interface AgentRunResult {
  reply: string;
  intent: "product_search" | "order_status" | "general_qa" | "cart_action";
  products?: Array<{
    id: string;
    title: string;
    price: string;
    handle: string;
    url: string;
    imageUrl: string;
    variantId?: string;
  }>;
  articles?: Array<{
    id: string;
    shopifyArticleId: string;
    blogHandle: string;
    blogTitle?: string | null;
    title: string;
    handle: string;
    summary?: string | null;
    content?: string | null;
    image?: string | null;
    imageUrl?: string | null;
    author?: string | null;
    url?: string | null;
    publishedAt?: Date | string | null;
  }>;
  orderInfo?: any;
}

/**
 * Main Multi-Tenant OpenAI Tool-Calling Agent Loop with iterative verification.
 */
export async function runAIAgentLoop({
  shopDomain,
  sessionId,
  userMessage,
  customerAccessToken,
}: AgentRunParams): Promise<AgentRunResult> {
  const tenant = await getTenantByDomain(shopDomain);
  const apiKey = process.env.OPENAI_API_KEY;

  // 1. Fetch Chatbot Settings
  const settings = await prisma.chatbotSettings.findUnique({
    where: { shopId: tenant.shopId },
  });

  const model = settings?.model || "gpt-4o-mini";
  const temperature = settings?.temperature ?? 0.7;

  // 2. Fetch Recent Conversation Memory
  const pastMessages = await prisma.message.findMany({
    where: { shopId: tenant.shopId, sessionId },
    orderBy: { createdAt: "asc" },
    take: 10,
  });

  // Fallback if no OpenAI Key configured
  if (!apiKey) {
    return runFallbackLocalAgent({ userMessage, shopDomain, sessionId, customerAccessToken });
  }

  // 3. Authoritative Backend Subscription Plan
  const activeSub = await SubscriptionService.getActiveSubscription(tenant.shopId);
  const plan = activeSub?.plan || "FREE";

  // Decoupled store-scoped context retrieval with intent extraction
  const extractedIntent = extractIntentAndFilters(userMessage);
  const storeProfile = await StoreProfileService.getStoreProfile({ shopId: tenant.shopId, shopifyDomain: shopDomain });
  const catalogRetrieval = await CatalogRetrievalService.getRelevantProducts({
    shopId: tenant.shopId,
    query: extractedIntent.queryText || userMessage,
    maxPrice: extractedIntent.maxPrice,
    maxResults: 5,
  });
  const policyRetrieval = await PolicyRetrievalService.getRelevantPoliciesAndKnowledge({
    shopId: tenant.shopId,
    query: extractedIntent.queryText || userMessage,
    intent: extractedIntent.intent,
  });
  const themeContext = await ThemeContextService.getThemeContext({ shopId: tenant.shopId, shopifyDomain: shopDomain });
  const planCapabilities = await PlanCapabilityService.getPlanCapabilities({ shopId: tenant.shopId, shopifyDomain: shopDomain });

  // Strict 5-Way Isolation Gate
  assertMultiStoreSafety({
    authenticatedShopId: tenant.shopId,
    retrievedProductShopId: catalogRetrieval.shopId,
    retrievedKnowledgeShopId: policyRetrieval.shopId,
    aiConfigShopId: tenant.shopId,
  });

  // 4. Construct System Prompt & Messages
  const systemPrompt = DynamicPromptBuilder.buildSystemPrompt({
    authenticatedShopId: tenant.shopId,
    shopDomain,
    shopName: settings?.botName,
    storeProfile,
    themeContext,
    catalogRetrieval,
    relevantPolicies: policyRetrieval.policies,
    merchantCustomPrompt: settings?.systemPrompt || undefined,
    planCapabilities,
    currencyCode: storeProfile.currency,
    languageCode: storeProfile.languages[0],
  });

  const messagesPayload: Array<any> = [
    { role: "system", content: systemPrompt },
    ...pastMessages.map((m) => ({
      role: m.role.toLowerCase(),
      content: m.content,
    })),
    { role: "user", content: userMessage },
  ];

  const toolsPayload = REGISTERED_AI_TOOLS.map((t) => ({
    type: "function",
    function: {
      name: t.name,
      description: t.description,
      parameters: t.parameters,
    },
  }));

  try {
    let currentMessages = [...messagesPayload];
    let accumulatedProducts: Array<any> = [];
    let accumulatedArticles: Array<any> = [];
    let accumulatedOrderInfo: any = undefined;
    let finalReply = "";
    let finalIntent: AgentRunResult["intent"] = "general_qa";
    const MAX_TOOL_ROUNDS = 5;

    // Check if user confirmed a pending destructive action in natural language
    const confirmationKey = `${sessionId}_${tenant.shopId}`;
    const pendingConfirmation = PENDING_CONFIRMATIONS.get(confirmationKey);
    const isUserConfirming =
      pendingConfirmation &&
      /^(yes|confirm|yes please|cancel order|proceed|approve)$/i.test(userMessage.trim());

    for (let round = 0; round < MAX_TOOL_ROUNDS; round++) {
      const aiRes = await fetch("https://api.openai.com/v1/chat/completions", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${apiKey}`,
        },
        body: JSON.stringify({
          model,
          messages: currentMessages,
          tools: toolsPayload,
          tool_choice: "auto",
          temperature,
        }),
      });

      if (!aiRes.ok) {
        const errText = await aiRes.text();
        logger.warn("OpenAI API call failed, falling back to local model", { status: aiRes.status, errText });
        return runFallbackLocalAgent({ userMessage, shopDomain, sessionId, customerAccessToken });
      }

      const data = await aiRes.json();
      const messageNode = data.choices?.[0]?.message;
      if (!messageNode) break;

      // If no tool calls, this is the final customer-facing response
      if (!messageNode.tool_calls || messageNode.tool_calls.length === 0) {
        finalReply = messageNode.content || "How else can I assist you with your shopping today?";
        break;
      }

      // Add assistant tool-request message to history
      currentMessages.push(messageNode);

      // Execute each tool call securely
      for (const toolCall of messageNode.tool_calls) {
        const toolName = toolCall.function.name;
        let toolArgs: Record<string, any> = {};

        try {
          toolArgs = JSON.parse(toolCall.function.arguments || "{}");
        } catch (jsonErr) {
          logger.warn("Malformed AI tool arguments", { toolName, shopId: tenant.shopId, sessionId });
          toolArgs = {};
        }

        const toolResult: any = await executeAITool({
          toolName,
          args: toolArgs,
          shopDomain,
          tenantShopId: tenant.shopId,
          sessionId,
          customerAccessToken,
          isUserConfirmed: isUserConfirming,
        });

        // Collect products, articles, or order info from verified tool results
        if (toolResult?.products && Array.isArray(toolResult.products) && toolResult.products.length > 0) {
          accumulatedProducts = [...accumulatedProducts, ...toolResult.products];
          finalIntent = "product_search";
        }
        if (toolResult?.articles && Array.isArray(toolResult.articles) && toolResult.articles.length > 0) {
          accumulatedArticles = [...accumulatedArticles, ...toolResult.articles];
        }
        if (toolResult?.orderInfo) {
          accumulatedOrderInfo = toolResult.orderInfo;
          finalIntent = "order_status";
        }
        if (toolResult?.intent) {
          finalIntent = toolResult.intent;
        }

        // Audit logging (strictly redacted)
        await prisma.toolExecution.create({
          data: {
            shopId: tenant.shopId,
            sessionId,
            toolName,
            arguments: redactSensitive(toolArgs) as any,
            result: redactSensitive(toolResult) as any,
            success: toolResult.success !== false,
            error: toolResult.error || null,
          },
        });

        // Feed verified tool output back to the LLM for formulation
        currentMessages.push({
          role: "tool",
          tool_call_id: toolCall.id,
          content: JSON.stringify(redactSensitive(toolResult)),
        });
      }
    }

    return {
      reply: finalReply || "How else can I assist you with your shopping today?",
      intent: finalIntent,
      products: accumulatedProducts.length > 0 ? accumulatedProducts : undefined,
      articles: accumulatedArticles.length > 0 ? accumulatedArticles : undefined,
      orderInfo: accumulatedOrderInfo,
    };
  } catch (error: any) {
    logger.error("Error in AI agent loop", { message: error.message });
    return runFallbackLocalAgent({ userMessage, shopDomain, sessionId, customerAccessToken });
  }
}

/**
 * Server-Side Tool Execution Handler with Authoritative Authorization & Confirmation.
 */
export async function executeAITool({
  toolName,
  args,
  shopDomain,
  tenantShopId,
  sessionId,
  customerAccessToken,
  isUserConfirmed,
}: {
  toolName: string;
  args: Record<string, any>;
  shopDomain: string;
  tenantShopId: string;
  sessionId: string;
  customerAccessToken?: string;
  isUserConfirmed?: boolean;
}): Promise<any> {
  logger.info("AI tool execution", {
    toolName,
    shopId: tenantShopId,
    sessionId,
  });

  const toolDef = REGISTERED_AI_TOOLS.find((t) => t.name === toolName);
  if (!toolDef) {
    return {
      success: false,
      status: "VALIDATION_ERROR",
      message: `Unknown tool "${toolName}".`,
      reply: "I cannot perform that action.",
    };
  }

  // Check 1: Server-Side Plan Authorization (Subscription is Authoritative via BillingService)
  const planInfo = await BillingService.getCurrentPlan(tenantShopId);
  const plan = planInfo?.plan || "FREE";
  const allowedTools = PLAN_TOOL_PERMISSIONS[plan] || PLAN_TOOL_PERMISSIONS.UNKNOWN;

  if (!allowedTools.has(toolName) || (toolDef.feature && !canUseFeature(plan, toolDef.feature))) {
    const isAIFeature =
      toolDef.feature?.startsWith("ai.") ||
      toolDef.feature === "openai" ||
      ["track_order", "get_customer_orders", "create_return", "cancel_order", "search_knowledge_base"].includes(
        toolName
      );
    const requiredPlan = isAIFeature ? "Pro" : "Starter";
    const userFacingAction =
      toolName === "create_cart" || toolName === "add_to_cart"
        ? "Add to Cart"
        : toolName === "update_cart_quantity"
        ? "Cart Management"
        : toolName === "calculate_shipping_rates"
        ? "Shipping Calculation"
        : toolName.replace(/_/g, " ");

    const message = `${userFacingAction} is available on the ${requiredPlan} plan and above. Upgrade to ${requiredPlan} to enable ${userFacingAction.toLowerCase()} features.`;

    return {
      success: false,
      status: "FEATURE_NOT_AVAILABLE",
      feature: toolDef.feature,
      message,
      reply: `<i class="fa fa-lock"></i> ${message}`,
      intent: "general_qa",
    };
  }

  // Check 2: Customer Authentication Requirement
  if (toolDef.authentication === "customer" && !customerAccessToken) {
    return {
      success: false,
      status: "UNAUTHORIZED",
      message: "Customer authentication is required for this operation.",
      reply: '<i class="fa fa-lock"></i> Please log in to your store account to view or manage your orders and profile.',
      intent: "general_qa",
    };
  }

  // Check 3: Destructive Action Confirmation Enforcement (Server Confirmation State)
  const confirmationKey = `${sessionId}_${tenantShopId}`;

  if (toolDef.confirmation === "required") {
    const existingPending = PENDING_CONFIRMATIONS.get(confirmationKey);

    // If not confirmed by the user in this session, register pending confirmation and prompt
    if (!isUserConfirmed && (!existingPending || existingPending.orderId !== args.orderId)) {
      PENDING_CONFIRMATIONS.set(confirmationKey, {
        action: toolName as "cancel_order" | "create_return",
        orderId: args.orderId || "this item",
        expiresAt: Date.now() + 10 * 60 * 1000,
        reason: args.reason,
      });

      return {
        success: false,
        status: "CONFIRMATION_REQUIRED",
        requiresConfirmation: true,
        message: `Confirmation required from customer before executing ${toolName}.`,
        reply: `⚠️ Are you sure you want to proceed with **${toolName.replace("_", " ")}** for order ${
          args.orderId || "this item"
        }? Please reply "Yes, confirm" to proceed.`,
        intent: "general_qa",
      };
    }

    // Confirmation verified; clear pending state
    PENDING_CONFIRMATIONS.delete(confirmationKey);
  }

  // --- Backend Tool Implementations ---

  // 1. Product Search Tool
  if (toolName === "search_products") {
    const searchResult = await searchProductsService(shopDomain, args.query || "", args.maxPrice);

    if (searchResult.status === "TECHNICAL_ERROR") {
      return {
        success: false,
        status: "TECHNICAL_ERROR",
        products: [],
        message: "Unable to connect to the store catalog right now.",
        reply: "I'm having trouble connecting to the store catalog right now. Please try again in a moment.",
        intent: "product_search",
      };
    }

    if (searchResult.status === "NO_MATCH" || searchResult.products.length === 0) {
      return {
        success: true,
        status: "NO_MATCH",
        products: [],
        message: searchResult.message || `No products matching "${args.query}" were found.`,
        reply: searchResult.message || `I couldn't find any products matching "${args.query}" in the store.`,
        intent: "product_search",
      };
    }

    const formattedProducts = searchResult.products.map((p) => {
      const rawVariants = Array.isArray(p.variants) ? p.variants : [];
      const formattedVariants = rawVariants.map((v: any) => ({
        id: String(v.shopifyVariantId || v.id || v.variantId || ""),
        title: v.title || "Default Title",
        price: formatCurrency(v.price ?? p.minPrice, p.currency),
        numericPrice: v.price ?? p.minPrice,
        compareAtPrice: v.compareAtPrice ? formatCurrency(v.compareAtPrice, p.currency) : null,
        available: v.available !== false,
      }));

      const firstAvailable = formattedVariants.find((v: any) => v.available) || formattedVariants[0];

      return {
        id: String(p.shopifyProductId || p.id),
        title: p.title,
        price: formatCurrency(p.minPrice, p.currency),
        handle: p.handle,
        url: `/products/${p.handle}`,
        imageUrl: p.image || "https://cdn.shopify.com/s/files/1/0533/2089/files/placeholder-images-product-1.png",
        variantId: firstAvailable?.id || "",
        variants: formattedVariants,
        available: formattedVariants.some((v: any) => v.available),
      };
    });

    return {
      success: true,
      status: "SUCCESS",
      products: formattedProducts,
      message: `Found ${formattedProducts.length} matching products.`,
      intent: "product_search",
    };
  }

  // 2. Product Details Tool
  if (toolName === "get_product_details") {
    const rawProducts = await searchProductsService(shopDomain, args.productHandle || "");
    const matched = rawProducts.products.find(
      (p) => p.handle === args.productHandle || p.shopifyProductId === args.productId
    );

    if (!matched) {
      return {
        success: true,
        status: "NO_MATCH",
        message: `Product details for "${args.productHandle || args.productId}" not found.`,
        intent: "product_search",
      };
    }

    return {
      success: true,
      status: "SUCCESS",
      product: matched,
      intent: "product_search",
    };
  }

  // 3. Cart Management Tools
  if (toolName === "create_cart" || toolName === "add_to_cart") {
    const cartRes = await createCartService(shopDomain, args.variantId, args.quantity || 1);
    return {
      success: cartRes.success,
      status: cartRes.success ? "SUCCESS" : "VALIDATION_ERROR",
      message: cartRes.message,
      reply: cartRes.success ? `<i class="fa fa-shopping-cart"></i> Item added to cart! [Click here to Checkout](${cartRes.checkoutUrl})` : cartRes.message,
      intent: "cart_action",
    };
  }

  // 4. Discount Code Tools
  if (toolName === "get_available_discount_codes") {
    return getAvailableDiscountCodesService(shopDomain);
  }

  if (toolName === "validate_discount_code") {
    return validateDiscountCodeService(shopDomain, args.code);
  }

  if (toolName === "apply_discount_code") {
    return applyDiscountService(shopDomain, args.code, args.cartId);
  }

  // 5. Shipping Rates Tool
  if (toolName === "calculate_shipping_rates") {
    return calculateShippingRatesService({
      shopDomain,
      country: args.country,
      zip: args.zip,
      province: args.province,
      city: args.city,
    });
  }

  // 6. Order Tracking & History Tools (Customer Authenticated & Scoped)
  if (toolName === "track_order") {
    return trackOrderSecurelyService({
      shopDomain,
      orderNumber: args.orderNumber,
      emailOrZip: args.emailOrZip,
    });
  }

  if (toolName === "get_customer_orders") {
    return getCustomerOrdersService({
      shopDomain,
      customerAccessToken: customerAccessToken!,
      orderId: args.orderId,
    });
  }

  // 7. Protected Destructive Actions
  if (toolName === "cancel_order") {
    return cancelOrderService({
      shopDomain,
      customerAccessToken: customerAccessToken!,
      orderId: args.orderId,
      confirmed: true,
      sessionId,
    });
  }

  if (toolName === "create_return") {
    return createReturnService({
      shopDomain,
      customerAccessToken: customerAccessToken!,
      orderId: args.orderId,
      reason: args.reason || "Not specified",
      confirmed: true,
      sessionId,
    });
  }

  // 8. Knowledge Base Search
  if (toolName === "search_knowledge_base") {
    const docs = await prisma.knowledgeBase.findMany({
      where: {
        shopId: tenantShopId,
        enabled: true,
        OR: [{ title: { contains: args.query } }, { content: { contains: args.query } }],
      },
      take: 3,
    });

    if (docs.length === 0) {
      return {
        success: true,
        status: "NO_MATCH",
        docs: [],
        message: `No published store policy found for "${args.query}".`,
        intent: "general_qa",
      };
    }

    return {
      success: true,
      status: "SUCCESS",
      docs: docs.map((d) => ({ title: d.title, content: d.content, category: d.sourceType })),
      reply: docs.map((d) => `• **${d.title}:** ${d.content}`).join("\n\n"),
      intent: "general_qa",
    };
  }

  // 8b. Store Blog Posts & Articles Search
  if (toolName === "search_blog_posts") {
    const articles = await searchArticlesService(shopDomain, args.query || "", 4);

    if (articles.length === 0) {
      return {
        success: true,
        status: "NO_MATCH",
        articles: [],
        message: `No store blog articles matching "${args.query}" were found.`,
        intent: "general_qa",
      };
    }

    return {
      success: true,
      status: "SUCCESS",
      articles,
      message: `Found ${articles.length} store blog articles matching "${args.query}".`,
      reply: articles.map((a) => `<i class="fa fa-book"></i> **[${a.blogTitle || 'Blog'}] ${a.title}:** ${a.summary || a.content?.substring(0, 180) + '...'}`).join("\n\n"),
      intent: "general_qa",
    };
  }

  if (toolName === "get_article_details") {
    const article = await getArticleDetailsService(shopDomain, args.articleHandle);

    if (!article) {
      return {
        success: false,
        status: "NOT_FOUND",
        message: `Article "${args.articleHandle}" was not found.`,
        intent: "general_qa",
      };
    }

    return {
      success: true,
      status: "SUCCESS",
      article,
      articles: [article],
      reply: `<i class="fa fa-book"></i> **${article.title}**\n\n${article.content || article.summary}`,
      intent: "general_qa",
    };
  }

  // 9. Human Support Escalation
  if (toolName === "handoff_to_human") {
    await prisma.analyticsEvent.create({
      data: {
        shopId: tenantShopId,
        sessionId,
        type: "handoff",
        metadata: { reason: args.reason },
      },
    });

    let settings = null;
    try {
      settings = await prisma.chatbotSettings.findUnique({
        where: { shopId: tenantShopId },
      });
    } catch (e) {}

    const { widgetTexts } = parseWidgetSettings(settings);
    const email = widgetTexts.storeSupportEmail || `support@${shopDomain}`;
    const phone = widgetTexts.storeSupportPhone;
    const hours = widgetTexts.storeSupportHours;
    const rawContactUrl = widgetTexts.storeContactUrl || "/pages/contact";
    const contactUrl = rawContactUrl.startsWith("http") ? rawContactUrl : `https://${shopDomain}${rawContactUrl.startsWith("/") ? "" : "/"}${rawContactUrl}`;

    const lines: string[] = [];
    if (phone) {
      const cleanPhone = phone.replace(/[^\d+]/g, "");
      const phoneLink = cleanPhone ? `[${phone}](tel:${cleanPhone})` : phone;
      lines.push(`• <i class="fa fa-phone"></i> **Phone / WhatsApp:** ${phoneLink}`);
    }
    lines.push(`• <i class="fa fa-envelope"></i> **Support Email:** [${email}](mailto:${email})`);
    if (hours) {
      lines.push(`• <i class="fa fa-clock"></i> **Hours:** ${hours}`);
    }
    lines.push(`• <i class="fa fa-globe"></i> **Contact Us Page:** [${contactUrl}](${contactUrl})`);

    const contactNote = `\n\n<i class="fa fa-phone"></i> **Store Support Details:**\n${lines.join("\n")}`;

    return {
      success: true,
      status: "SUCCESS",
      reply: `<i class="fa fa-handshake"></i> I have forwarded your request to our store customer support team regarding: "${args.reason}". A representative will get back to you shortly.${contactNote}`,
      intent: "general_qa",
    };
  }

  // 10. Store Contact Info Tool
  if (toolName === "get_store_contact_info") {
    let settings = null;
    try {
      settings = await prisma.chatbotSettings.findUnique({
        where: { shopId: tenantShopId },
      });
    } catch (e) {}

    const { widgetTexts } = parseWidgetSettings(settings);
    const email = widgetTexts.storeSupportEmail || `support@${shopDomain}`;
    const phone = widgetTexts.storeSupportPhone;
    const hours = widgetTexts.storeSupportHours;
    const address = widgetTexts.storeAddress;
    const rawContactUrl = widgetTexts.storeContactUrl || "/pages/contact";
    const contactUrl = rawContactUrl.startsWith("http") ? rawContactUrl : `https://${shopDomain}${rawContactUrl.startsWith("/") ? "" : "/"}${rawContactUrl}`;

    const lines: string[] = [];
    if (phone) {
      const cleanPhone = phone.replace(/[^\d+]/g, "");
      const phoneLink = cleanPhone ? `[${phone}](tel:${cleanPhone})` : phone;
      lines.push(`• **Phone / WhatsApp:** ${phoneLink}`);
    }
    lines.push(`• **Support Email:** [${email}](mailto:${email})`);
    if (hours) {
      lines.push(`• **Operating Hours:** ${hours}`);
    }
    if (address) {
      lines.push(`• **Location / Address:** ${address}`);
    }
    lines.push(`• **Contact Us Page:** [Visit Contact Us](${contactUrl})`);

    const reply = `Here is our store's customer support and contact information:\n\n${lines.join("\n")}\n\nFeel free to reach out to us directly if you have any questions!`;

    return {
      success: true,
      status: "SUCCESS",
      reply,
      intent: "general_qa",
    };
  }

  return {
    success: false,
    status: "VALIDATION_ERROR",
    message: `Tool ${toolName} execution not implemented.`,
  };
}

async function runFallbackLocalAgent({
  userMessage,
  shopDomain,
  sessionId,
  customerAccessToken,
}: {
  userMessage: string;
  shopDomain: string;
  sessionId?: string;
  customerAccessToken?: string;
}): Promise<AgentRunResult> {
  const gemini = new GeminiProvider();
  const res = await gemini.generateResponse({
    shopDomain,
    sessionId: sessionId || `session_${Date.now()}`,
    userMessage,
    customerAccessToken,
  });

  return {
    reply: res.reply,
    intent: (res.intent as "order_status" | "general_qa" | "product_search" | "cart_action") || "general_qa",
    products: res.products,
    articles: res.articles,
    orderInfo: res.orderInfo,
  };
}
