import type { ActionFunctionArgs, LoaderFunctionArgs } from "react-router";
import { getTenantByDomain } from "../lib/security/tenant-context";
import { runUniversalAIAgent } from "../lib/ai/provider";
import { runLocalShopifyFallback } from "../lib/ai/local-provider";
import { canUseFeature } from "../lib/billing-plans";
import { checkRateLimit } from "../lib/security/rate-limit";
import { logger } from "../lib/security/logger";
import { AppError } from "../lib/security/errors";
import { checkUsageLimit, incrementUsage } from "../services/billing.server";
import prisma from "../db.server";
import { getDefaultStoreDomainSync } from "../services/platform-settings.server";

const corsHeaders = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Methods": "POST, GET, OPTIONS",
  "Access-Control-Allow-Headers": "Content-Type, Authorization, X-Requested-With",
  "Content-Type": "application/json",
  "Cache-Control": "no-cache, no-store, must-revalidate, max-age=0",
  "Pragma": "no-cache",
  "Expires": "0",
};

export const loader = async ({ request }: LoaderFunctionArgs) => {
  if (request.method === "OPTIONS") {
    return new Response(null, { status: 204, headers: corsHeaders });
  }
  return new Response(JSON.stringify({ status: "Chat message endpoint ready" }), { headers: corsHeaders });
};

export const action = async ({ request }: ActionFunctionArgs) => {
  if (request.method === "OPTIONS") {
    return new Response(null, { status: 204, headers: corsHeaders });
  }

  try {
    const url = new URL(request.url);
    const queryShop = url.searchParams.get("shop");
    let body: any = {};

    try {
      const text = await request.text();
      if (text) {
        body = JSON.parse(text);
      }
    } catch (parseErr) {
      logger.warn("Validation failure in /api/chat/message: Malformed JSON body payload");
      return new Response(
        JSON.stringify({ success: false, error: "Invalid JSON body payload" }),
        { status: 400, headers: corsHeaders }
      );
    }

    const { message, shop: bodyShop, sessionId: bodySessionId, customerAccessToken } = body || {};
    const shop = (bodyShop || queryShop || getDefaultStoreDomainSync()).toLowerCase().trim();

    if (!shop) {
      logger.warn("Validation failure in /api/chat/message: Shop parameter is missing");
      return new Response(
        JSON.stringify({ success: false, error: "Shop parameter is required" }),
        { status: 400, headers: corsHeaders }
      );
    }

    if (!message || typeof message !== "string" || message.trim() === "") {
      logger.warn("Validation failure in /api/chat/message: Required 'message' parameter is missing or empty", { shop });
      return new Response(
        JSON.stringify({ success: false, error: "Message parameter is required" }),
        { status: 400, headers: corsHeaders }
      );
    }

    // Rate Limit Guard (60 requests / min per shop)
    checkRateLimit({ key: `msg_${shop}`, maxTokens: 60, refillIntervalMs: 60000 });

    // 1. Resolve Tenant Context safely
    const tenant = await getTenantByDomain(shop);

    // 2. Validate or Auto-Create Chat Session safely
    const sessionId = bodySessionId || `anon_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
    let chatSession = await prisma.chatSession.findFirst({
      where: { id: sessionId, shopId: tenant.shopId },
    });

    if (!chatSession) {
      chatSession = await prisma.chatSession.create({
        data: {
          id: sessionId,
          shopId: tenant.shopId,
          anonymousSessionId: sessionId,
          status: "ACTIVE",
        },
      });
    }

    // 1. Enforce Plan Capability & AI Quota
    const usageCheck = await checkUsageLimit(tenant.shopId);
    const hasAIAccess = canUseFeature(usageCheck.plan, "openai");

    // 3. Persist User Message in DB
    await prisma.message.create({
      data: {
        shopId: tenant.shopId,
        sessionId: chatSession.id,
        role: "USER",
        sender: "CUSTOMER",
        content: message,
      },
    });

    // 1b. Enforce Plan Capability:
    // FREE & STARTER plans do NOT call OpenAI or Gemini API - they use the fast Local Catalog & Knowledge Engine
    if (!hasAIAccess) {
      const localResult = await runLocalShopifyFallback({
        shopDomain: tenant.shopifyDomain,
        sessionId: chatSession.id,
        userMessage: message,
        customerAccessToken,
      });

      // Persist Assistant Reply in DB
      await prisma.message.create({
        data: {
          shopId: tenant.shopId,
          sessionId: chatSession.id,
          role: "ASSISTANT",
          sender: "BOT",
          content: localResult.reply,
          metadata: (localResult.products || localResult.articles) ? { products: localResult.products, articles: localResult.articles } : undefined,
        },
      });

      return new Response(
        JSON.stringify({
          success: true,
          reply: localResult.reply,
          intent: localResult.intent || "general_qa",
          products: localResult.products || [],
          articles: localResult.articles || [],
          orderInfo: localResult.orderInfo,
        }),
        { headers: corsHeaders }
      );
    }

    // 1c. Enforce Pro Monthly AI Quota (25,000 requests/mo)
    if (usageCheck.limitReached) {
      // If AI limit reached on Pro, gracefully fallback to local store engine
      const localResult = await runLocalShopifyFallback({
        shopDomain: tenant.shopifyDomain,
        sessionId: chatSession.id,
        userMessage: message,
        customerAccessToken,
      });

      await prisma.message.create({
        data: {
          shopId: tenant.shopId,
          sessionId: chatSession.id,
          role: "ASSISTANT",
          sender: "BOT",
          content: localResult.reply,
          metadata: (localResult.products || localResult.articles) ? { products: localResult.products, articles: localResult.articles } : undefined,
        },
      });

      return new Response(
        JSON.stringify({
          success: true,
          reply: localResult.reply,
          intent: localResult.intent || "general_qa",
          products: localResult.products || [],
          articles: localResult.articles || [],
          orderInfo: localResult.orderInfo,
        }),
        { headers: corsHeaders }
      );
    }

    // 4. Run Universal AI Agent for PRO Tier (OpenAI / Gemini)
    const aiResult = await runUniversalAIAgent({
      shopDomain: tenant.shopifyDomain,
      sessionId: chatSession.id,
      userMessage: message,
      customerAccessToken,
    });

    // 5. Persist Assistant Reply in DB
    await prisma.message.create({
      data: {
        shopId: tenant.shopId,
        sessionId: chatSession.id,
        role: "ASSISTANT",
        sender: "BOT",
        content: aiResult.reply,
        metadata: (aiResult.products || aiResult.articles) ? { products: aiResult.products, articles: aiResult.articles } : undefined,
      },
    });

    // 6. Record Usage Record & Increment Active Pro Subscription Counter
    await prisma.usageRecord.create({
      data: {
        shopId: tenant.shopId,
        sessionId: chatSession.id,
        type: "ai_message",
        quantity: 1,
      },
    });

    await incrementUsage(tenant.shopId);

    return new Response(
      JSON.stringify({
        success: true,
        reply: aiResult.reply,
        intent: aiResult.intent,
        products: aiResult.products || [],
        articles: aiResult.articles || [],
        orderInfo: aiResult.orderInfo,
      }),
      { headers: corsHeaders }
    );
  } catch (error: any) {
    if (error instanceof AppError) {
      logger.warn(`Validation failure in /api/chat/message: ${error.message}`, {
        code: error.code,
        statusCode: error.statusCode,
      });
      const isUninstalled = error.statusCode === 403 || String(error.message).toLowerCase().includes("uninstalled");
      return new Response(
        JSON.stringify({
          success: false,
          isUninstalled,
          error: error.message,
          reply: isUninstalled ? "Chatbot is disabled because this store is currently uninstalled or inactive." : error.message,
          products: [],
        }),
        { status: error.statusCode, headers: corsHeaders }
      );
    }

    logger.error("Failed to process chat message in AI loop", error);
    return new Response(
      JSON.stringify({
        success: false,
        error: error.message || "Failed to process message",
        reply: "I'm having a little trouble processing your message right now. How else can I assist you?",
        products: [],
      }),
      { status: 500, headers: corsHeaders }
    );
  }
};
