import prisma from "../../db.server";
import { TenantAccessDeniedError } from "./errors";
import { registerShop } from "../../services/shop.server";

export interface TenantContext {
  shopId: string;
  shopifyDomain: string;
  scopes: string;
  installedAt: Date;
}

/**
 * Resolves the authenticated Shop tenant from a verified shopify domain.
 * NEVER trusts raw client input without domain validation.
 */
export async function getTenantByDomain(shopifyDomain: string): Promise<TenantContext> {
  if (!shopifyDomain) {
    throw new TenantAccessDeniedError("Shopify domain is required to resolve tenant context");
  }

  const normalizedDomain = shopifyDomain.toLowerCase().trim();

  let shop = await prisma.shop.findUnique({
    where: { shopifyDomain: normalizedDomain },
  });

  if (!shop) {
    throw new TenantAccessDeniedError(`Tenant store ${normalizedDomain} is not registered`);
  }

  if (shop.uninstalledAt) {
    throw new TenantAccessDeniedError(`Tenant shop ${normalizedDomain} uninstalled`);
  }

  return {
    shopId: shop.id,
    shopifyDomain: shop.shopifyDomain,
    scopes: shop.scopes,
    installedAt: shop.installedAt,
  };
}

/**
 * Enforces that a database query scope matches the current tenant.
 * Guarantees cross-tenant boundary isolation.
 */
export function assertTenantScope(requestedShopId: string, currentShopId: string): void {
  if (!requestedShopId || requestedShopId !== currentShopId) {
    throw new TenantAccessDeniedError("Cross-tenant access violation blocked");
  }
}

import { getDefaultStoreDomainSync } from "../../services/platform-settings.server";

/**
 * Dynamically resolves Shopify store domain from URL params, App Bridge host param, Bearer JWT, Referer, or fallback.
 */
export function resolveShopDomainFromRequest(request: Request, fallbackDomain?: string): string {
  const defaultDomain = fallbackDomain || getDefaultStoreDomainSync();
  const url = new URL(request.url);

  // 1. Direct query parameter ?shop=...
  const shopParam = url.searchParams.get("shop");
  if (shopParam && shopParam.trim().length > 0) {
    let clean = shopParam.toLowerCase().trim();
    if (!clean.includes(".")) clean = `${clean}.myshopify.com`;
    return clean;
  }

  // 2. Host parameter (Base64 encoded string from Shopify App Bridge: e.g. admin.shopify.com/store/your-store-handle)
  const hostParam = url.searchParams.get("host");
  if (hostParam) {
    try {
      const decodedHost = Buffer.from(hostParam, "base64").toString("utf8");
      const storeMatch = decodedHost.match(/admin\.shopify\.com\/store\/([a-zA-Z0-9_-]+)/i);
      if (storeMatch && storeMatch[1]) {
        return `${storeMatch[1].toLowerCase()}.myshopify.com`;
      }
      const myShopMatch = decodedHost.match(/([a-zA-Z0-9_-]+\.myshopify\.com)/i);
      if (myShopMatch && myShopMatch[1]) {
        return myShopMatch[1].toLowerCase();
      }
    } catch (e) {}
  }

  // 3. Authorization Bearer JWT header
  const authHeader = request.headers.get("Authorization");
  if (authHeader && authHeader.startsWith("Bearer ")) {
    try {
      const jwtToken = authHeader.replace("Bearer ", "");
      const payloadBase64 = jwtToken.split(".")[1];
      if (payloadBase64) {
        const payloadJson = JSON.parse(Buffer.from(payloadBase64, "base64").toString("utf8"));
        if (payloadJson.dest) {
          const cleanDest = payloadJson.dest.replace(/^https?:\/\//, "").toLowerCase().trim();
          if (cleanDest) return cleanDest;
        }
      }
    } catch (e) {}
  }

  // 4. Referer Header
  const referer = request.headers.get("Referer");
  if (referer) {
    try {
      const refUrl = new URL(referer);
      const refShop = refUrl.searchParams.get("shop");
      if (refShop) return refShop.toLowerCase().trim();
      const refStoreMatch = refUrl.pathname.match(/\/store\/([a-zA-Z0-9_-]+)/i);
      if (refStoreMatch && refStoreMatch[1]) {
        return `${refStoreMatch[1].toLowerCase()}.myshopify.com`;
      }
    } catch (e) {}
  }

  return defaultDomain;
}

