import prisma from "../db.server";
import { encryptToken, decryptToken } from "../lib/security/encryption";

export interface RegisterShopParams {
  shopifyDomain: string;
  shopifyShopId?: string;
  shopifyAppId?: string;
  accessToken: string;
  refreshToken?: string;
  tokenExpiresAt?: Date;
  scopes: string;
  isReinstall?: boolean;
}

/**
 * Registers or updates a multi-tenant Shop record with AES-256 encrypted tokens.
 */
export async function registerShop(params: RegisterShopParams) {
  const normalizedDomain = params.shopifyDomain.toLowerCase().trim();
  const existingShop = await prisma.shop.findUnique({ where: { shopifyDomain: normalizedDomain } });

  const shouldUpdateToken = params.accessToken !== "shpss_sample_token" || !existingShop;
  const encryptedToken = shouldUpdateToken ? encryptToken(params.accessToken) : existingShop.accessToken;
  const encryptedRefreshToken = params.refreshToken ? encryptToken(params.refreshToken) : (existingShop?.refreshToken || null);

  // Automatically activate store on install / reinstall
  const wasUninstalled = Boolean(existingShop?.uninstalledAt);
  const uninstalledAt = null;
  const installedAt = wasUninstalled ? new Date() : (existingShop?.installedAt || new Date());

  const shop = await prisma.shop.upsert({
    where: { shopifyDomain: normalizedDomain },
    update: {
      shopifyShopId: params.shopifyShopId || existingShop?.shopifyShopId,
      shopifyAppId: params.shopifyAppId || existingShop?.shopifyAppId,
      accessToken: encryptedToken,
      refreshToken: encryptedRefreshToken,
      tokenExpiresAt: params.tokenExpiresAt || existingShop?.tokenExpiresAt,
      scopes: params.scopes,
      uninstalledAt,
      installedAt,
      updatedAt: new Date(),
    },
    create: {
      shopifyDomain: normalizedDomain,
      shopifyShopId: params.shopifyShopId,
      shopifyAppId: params.shopifyAppId,
      accessToken: encryptedToken,
      refreshToken: encryptedRefreshToken,
      tokenExpiresAt: params.tokenExpiresAt,
      scopes: params.scopes,
      uninstalledAt: null,
      installedAt: new Date(),
    },
  });

  // Ensure default ChatbotSettings record exists and chatbot is enabled
  const existingSettings = await prisma.chatbotSettings.findUnique({ where: { shopId: shop.id } });
  if (existingSettings) {
    if (wasUninstalled || params.isReinstall) {
      // Re-enable chatbot on install / reinstall
      const { parseWidgetSettings, serializeWidgetSettings } = await import("./widget-settings.server");
      const { systemPromptText, widgetTexts } = parseWidgetSettings(existingSettings);
      widgetTexts.adminDisabled = false;
      const serialized = serializeWidgetSettings(systemPromptText, widgetTexts);
      await prisma.chatbotSettings.update({
        where: { shopId: shop.id },
        data: {
          enabled: true,
          systemPrompt: serialized,
        },
      });
    }
  } else {
    await prisma.chatbotSettings.create({
      data: {
        shopId: shop.id,
        botName: "ShopPilot AI Assistant",
        welcomeMessage: "Hi! How can I help you find products, calculate shipping, or track orders today?",
        primaryColor: "#4F46E5",
        secondaryColor: "#4338CA",
        textColor: "#FFFFFF",
        botTextColor: "#1F2937",
        showPoweredBy: true,
        position: "bottom-right",
        enabled: true,
        model: "gpt-4o-mini",
      },
    });
  }

  // Ensure default SystemIntegration record exists in dedicated system_integrations table
  await prisma.systemIntegration.upsert({
    where: { id: "global" },
    update: {},
    create: {
      id: "global",
      aiProvider: "openai",
      openaiModel: "gpt-4o-mini",
      openaiTemperature: 0.7,
      openaiMaxTokens: 1000,
      openaiEnabled: true,
      geminiModel: "gemini-1.5-flash",
      geminiTemperature: 0.7,
      geminiMaxTokens: 1000,
      geminiEnabled: true,
    },
  });

  // Ensure default/active Subscription is synced via BillingService
  try {
    const { BillingService } = await import("./billing.server");
    await BillingService.getActiveSubscription(shop.shopifyDomain);
  } catch (billingErr) {
    // If billing sync encounters an error, ensure local Free subscription exists
    const activeSub = await prisma.subscription.findFirst({
      where: { shopId: shop.id, status: "ACTIVE" },
    });
    if (!activeSub) {
      const now = new Date();
      const perpetualEnd = new Date(now.getTime() + 3650 * 24 * 60 * 60 * 1000);
      await prisma.subscription.create({
        data: {
          id: `sub_${shop.id}_${Date.now()}`,
          shopId: shop.id,
          plan: "FREE",
          status: "ACTIVE",
          price: 0.0,
          currency: "USD",
          billingInterval: "MONTHLY",
          monthlyLimit: 0,
          currentUsage: 0,
          startedAt: now,
          billingPeriodStart: now,
          billingPeriodEnd: perpetualEnd,
        },
      });
    }
  }

  // Trigger initial Store Intelligence discovery asynchronously in background
  import("./store-intelligence.server")
    .then(({ StoreIntelligenceService }) => StoreIntelligenceService.analyzeStoreAndBuildProfile(shop.id, shop.shopifyDomain))
    .catch(() => {});

  return shop;
}

/**
 * Gets a Shop and returns the decrypted access token.
 */
export async function getShopWithDecryptedToken(shopifyDomain: string) {
  const normalizedDomain = shopifyDomain.toLowerCase().trim();
  const shop = await prisma.shop.findUnique({
    where: { shopifyDomain: normalizedDomain },
  });

  if (!shop) return null;

  return {
    ...shop,
    decryptedAccessToken: decryptToken(shop.accessToken),
    decryptedRefreshToken: shop.refreshToken ? decryptToken(shop.refreshToken) : null,
  };
}

/**
 * Ensures an active, non-expired offline access token is returned for Shopify Admin API calls.
 * Automatically exchanges legacy non-expiring tokens for expiring tokens and refreshes expired tokens.
 */
export async function getValidAdminAccessToken(shopDomainOrRecord: any): Promise<string> {
  const domain = typeof shopDomainOrRecord === "string" ? shopDomainOrRecord : shopDomainOrRecord?.shopifyDomain;
  if (!domain) return "";

  const normalizedDomain = domain.includes(".") ? domain.toLowerCase().trim() : `${domain.toLowerCase().trim()}.myshopify.com`;
  const shop = await prisma.shop.findUnique({ where: { shopifyDomain: normalizedDomain } });
  if (!shop) return "";

  const apiKey = process.env.SHOPIFY_API_KEY || "ff484160a48beda29e79144ee4e9a819";
  const apiSecret = process.env.SHOPIFY_API_SECRET || "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";

  let accessToken = "";
  if (shop.accessToken) {
    try {
      const decrypted = decryptToken(shop.accessToken.trim());
      if (decrypted && !decrypted.startsWith("shpss_sample_token")) {
        accessToken = decrypted;
      }
    } catch {
      if (shop.accessToken.startsWith("shpat_") || shop.accessToken.startsWith("shpua_")) {
        accessToken = shop.accessToken.trim();
      }
    }
  }

  const refreshToken = shop.refreshToken ? decryptToken(shop.refreshToken.trim()) : "";
  const tokenExpiresAt = shop.tokenExpiresAt ? new Date(shop.tokenExpiresAt) : null;
  const now = new Date();

  // 1. Proactive Token Refresh: If token expires within 5 minutes and refreshToken exists
  if (refreshToken && tokenExpiresAt && now > new Date(tokenExpiresAt.getTime() - 5 * 60 * 1000)) {
    try {
      const refreshParams = new URLSearchParams({
        client_id: apiKey,
        client_secret: apiSecret,
        grant_type: "refresh_token",
        refresh_token: refreshToken,
      });

      const refreshRes = await fetch(`https://${normalizedDomain}/admin/oauth/access_token`, {
        method: "POST",
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
        body: refreshParams.toString(),
      });

      if (refreshRes.ok) {
        const json = await refreshRes.json();
        if (json.access_token) {
          accessToken = json.access_token;
          const newRefreshToken = json.refresh_token || refreshToken;
          const expiresIn = Number(json.expires_in || 3600);
          const newExpiresAt = new Date(Date.now() + expiresIn * 1000);

          await registerShop({
            shopifyDomain: normalizedDomain,
            accessToken,
            refreshToken: newRefreshToken,
            tokenExpiresAt: newExpiresAt,
            scopes: shop.scopes,
          });
          return accessToken;
        }
      } else {
        const errText = await refreshRes.text();
        console.warn("[getValidAdminAccessToken] Proactive token refresh HTTP status:", refreshRes.status, errText);
      }
    } catch (refreshErr) {
      console.warn("[getValidAdminAccessToken] Proactive token refresh failed:", refreshErr);
    }
  }

  // 2. Token Exchange Migration: If token is legacy non-expiring (starts with shpat_ or no tokenExpiresAt)
  if (accessToken && (!tokenExpiresAt || accessToken.startsWith("shpat_"))) {
    const migrated = await forceMigrateToken(normalizedDomain, accessToken, shop.scopes);
    if (migrated) {
      return migrated;
    }
  }

  return accessToken;
}

/**
 * Explicitly forces token exchange migration for a shop from legacy non-expiring token to an expiring offline token.
 */
export async function forceMigrateToken(shopDomain: string, currentToken?: string, scopes?: string): Promise<string | null> {
  const normalizedDomain = shopDomain.includes(".") ? shopDomain.toLowerCase().trim() : `${shopDomain.toLowerCase().trim()}.myshopify.com`;
  const apiKey = process.env.SHOPIFY_API_KEY || "ff484160a48beda29e79144ee4e9a819";
  const apiSecret = process.env.SHOPIFY_API_SECRET || "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";

  let tokenToExchange = currentToken;
  let shopScopes = scopes;

  if (!tokenToExchange) {
    const shop = await prisma.shop.findUnique({ where: { shopifyDomain: normalizedDomain } });
    if (!shop || !shop.accessToken) return null;
    shopScopes = shop.scopes;
    try {
      const decrypted = decryptToken(shop.accessToken.trim());
      if (decrypted && !decrypted.startsWith("shpss_sample_token")) {
        tokenToExchange = decrypted;
      }
    } catch {
      tokenToExchange = shop.accessToken.trim();
    }
  }

  if (!tokenToExchange || tokenToExchange.startsWith("shpss_sample_token")) {
    return null;
  }

  try {
    const migrateParams = new URLSearchParams({
      client_id: apiKey,
      client_secret: apiSecret,
      grant_type: "urn:ietf:params:oauth:grant-type:token-exchange",
      subject_token: tokenToExchange,
      subject_token_type: "urn:shopify:params:oauth:token-type:offline-access-token",
      requested_token_type: "urn:shopify:params:oauth:token-type:offline-access-token",
      expiring: "1",
    });

    const migrateRes = await fetch(`https://${normalizedDomain}/admin/oauth/access_token`, {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: migrateParams.toString(),
    });

    if (migrateRes.ok) {
      const json = await migrateRes.json();
      if (json.access_token) {
        console.log("[forceMigrateToken] Successfully exchanged legacy token for expiring offline token for", normalizedDomain);
        const newAccessToken = json.access_token;
        const newRefreshToken = json.refresh_token || null;
        const expiresIn = Number(json.expires_in || 3600);
        const newExpiresAt = new Date(Date.now() + expiresIn * 1000);

        await registerShop({
          shopifyDomain: normalizedDomain,
          accessToken: newAccessToken,
          refreshToken: newRefreshToken,
          tokenExpiresAt: newExpiresAt,
          scopes: shopScopes || "read_products,read_content,read_orders,write_orders,read_customers,write_customers",
        });
        return newAccessToken;
      }
    } else {
      const errText = await migrateRes.text();
      console.warn("[forceMigrateToken] Token migration failed HTTP status:", migrateRes.status, errText);
    }
  } catch (migErr) {
    console.warn("[forceMigrateToken] Token migration exception:", migErr);
  }

  return null;
}
