import crypto from "crypto";
import prisma from "../../db.server";
import { logger } from "../security/logger";
import { upsertSingleProductCache, deleteProductCache } from "../../services/catalog.server";

/**
 * Validates Shopify Webhook HMAC SHA256 Signature in constant time.
 * FAILS CLOSED: Never bypasses validation when secret is missing.
 */
export function verifyShopifyWebhookHmac(rawBody: string, hmacHeader: string | null): boolean {
  if (!hmacHeader) return false;
  const secret = process.env.SHOPIFY_API_SECRET || "";
  if (!secret) {
    logger.error("SHOPIFY_API_SECRET is not configured in environment");
    return false;
  }

  try {
    const calculatedHmac = crypto
      .createHmac("sha256", secret)
      .update(rawBody, "utf8")
      .digest("base64");

    const calcBuf = Buffer.from(calculatedHmac, "utf8");
    const headerBuf = Buffer.from(hmacHeader, "utf8");

    if (calcBuf.length !== headerBuf.length) {
      return false;
    }

    return crypto.timingSafeEqual(calcBuf, headerBuf);
  } catch (e) {
    return false;
  }
}

/**
 * Idempotent Webhook Event Processor.
 */
export async function processWebhookEvent({
  webhookId,
  topic,
  shopDomain,
  payload,
}: {
  webhookId: string;
  topic: string;
  shopDomain: string;
  payload: any;
}): Promise<{ processed: boolean; duplicate: boolean }> {
  try {
    // Check if webhook has already been processed (Idempotency check)
    let existing = null;
    try {
      existing = await prisma.webhookEvent.findUnique({
        where: { webhookId },
      });
    } catch (dbErr: any) {
      logger.warn(`Idempotency check query warning: ${dbErr.message}`, { webhookId });
    }

    if (existing) {
      logger.info(`Duplicate webhook received: ${webhookId} (${topic})`, { webhookId, topic, shopDomain });
      return { processed: existing.processed, duplicate: true };
    }

    let shop = null;
    try {
      if (shopDomain) {
        shop = await prisma.shop.findUnique({
          where: { shopifyDomain: shopDomain },
        });
      }
    } catch (dbErr: any) {
      logger.warn(`Failed to find shop for domain ${shopDomain}: ${dbErr.message}`);
    }

    // Record Webhook Event
    let event: any = null;
    try {
      event = await prisma.webhookEvent.create({
        data: {
          webhookId,
          topic,
          shopId: shop?.id || null,
          payload: payload && typeof payload === "object" ? payload : {},
          processed: false,
        },
      });
    } catch (dbErr: any) {
      logger.warn(`Could not persist WebhookEvent record: ${dbErr.message}`, { webhookId });
    }

    // Handle specific webhook topics
    try {
      if (topic === "app/uninstalled") {
        if (shop) {
          await prisma.shop.update({
            where: { id: shop.id },
            data: {
              uninstalledAt: new Date(),
              accessToken: "shpss_sample_token",
              refreshToken: null,
              tokenExpiresAt: null,
            },
          });
          logger.info(`Merchant app uninstalled: ${shopDomain}`, { shopId: shop.id, shopDomain });
        } else if (shopDomain) {
          await prisma.shop.updateMany({
            where: { shopifyDomain: shopDomain },
            data: {
              uninstalledAt: new Date(),
              accessToken: "shpss_sample_token",
              refreshToken: null,
              tokenExpiresAt: null,
            },
          });
          logger.info(`Merchant app uninstalled (by domain): ${shopDomain}`);
        }
      } else if (topic === "products/create" || topic === "products/update") {
        if (shopDomain && payload) {
          await upsertSingleProductCache(shopDomain, payload);
          logger.info(`Real-time ProductCache updated for ${shopDomain} (Product ID: ${payload.id})`, { topic, shopDomain });
        }
      } else if (topic === "products/delete") {
        if (shopDomain && payload?.id) {
          await deleteProductCache(shopDomain, String(payload.id));
          logger.info(`Real-time ProductCache item deleted for ${shopDomain} (Product ID: ${payload.id})`, { topic, shopDomain });
        }
      } else if (topic === "customers/redact") {
        if (shop && payload?.customer?.id) {
          await prisma.customer.deleteMany({
            where: { shopId: shop.id, shopifyCustomerId: String(payload.customer.id) },
          });
          logger.info(`GDPR customer data redacted for ${shopDomain}`, { customerId: payload.customer.id });
        }
      }
    } catch (err: any) {
      logger.error(`Error executing webhook handler for ${topic}: ${err.message}`, err);
    }

    // Mark event as processed
    if (event?.id) {
      try {
        await prisma.webhookEvent.update({
          where: { id: event.id },
          data: { processed: true },
        });
      } catch (dbErr: any) {
        logger.warn(`Could not mark WebhookEvent as processed: ${dbErr.message}`, { eventId: event.id });
      }
    }

    return { processed: true, duplicate: false };
  } catch (err: any) {
    logger.error(`Fatal unhandled error processing webhook ${topic}: ${err.message}`, err);
    return { processed: false, duplicate: false };
  }
}
