import prisma from "../db.server";
import { PlanTier, SubscriptionStatus } from "@prisma/client";
import { PLAN_CONFIGS, PlanDetails, FeatureKey, canUseFeature } from "../lib/billing-plans";
import { logger } from "../lib/security/logger";
import { decryptToken } from "../lib/security/encryption";
import {
  queryPartnerActiveSubscription,
  mapActiveSubscriptionToPlan,
  getShopifyPricingPlansUrl,
  getShopifyEmbeddedAppUrl,
  ResolvedSubscriptionState,
  formatShopifyGid,
} from "./shopify-partner.server";


export { PLAN_CONFIGS };
export type { PlanDetails };

export type BillingStatusState =
  | "NO_SUBSCRIPTION"
  | "FREE"
  | "STARTER"
  | "PRO"
  | "TRIAL"
  | "CANCELLED_AT_END"
  | "SUBSCRIPTION_LOOKUP_ERROR"
  | "SHOPIFY_AUTH_ERROR";

export interface CurrentPlanInfo {
  shopDomain: string;
  shopId: string;
  shopifyShopId: string | null;
  shopifyAppId: string | null;
  plan: PlanTier;
  planHandle: string;
  displayName: string;
  price: number;
  currency: string;
  billingPeriod: string;
  status: SubscriptionStatus;
  statusState: BillingStatusState;
  isTrial: boolean;
  trialEndsAt: Date | null;
  cancelAtEndOfCycle: boolean;
  currentBillingCycleStart: Date | null;
  currentBillingCycleEnd: Date | null;
  lastSubscriptionSync: Date | null;
  pricingPlansUrl: string;
  description?: string;
  features: string[];
}

const PLAN_HIERARCHY: Record<PlanTier, number> = {
  FREE: 1,
  STARTER: 2,
  GROWTH: 3,
  PRO: 3,
};

/**
 * Centralized Shopify App Pricing Billing Service.
 * Canonical server-side manager for subscription synchronization, plan detection, and feature gating.
 */
export class BillingService {
  /**
   * Resolves the official Shopify-hosted plan selection URL for a given shop.
   */
  static getPricingUrl(shopDomain: string, appHandle?: string): string {
    return getShopifyPricingPlansUrl(shopDomain, appHandle);
  }

  /**
   * Resolves the official Shopify embedded app URL for a given shop.
   * Pattern: https://admin.shopify.com/store/:store_handle/apps/:app_handle
   */
  static getEmbeddedAppUrl(shopDomain: string, appHandle?: string): string {
    return getShopifyEmbeddedAppUrl(shopDomain, appHandle);
  }

  /**
   * Creates a Shopify app subscription using Shopify's official billing API.
   * Never processes merchant payment details.
   * Returns the Shopify confirmation URL that sends the merchant into Shopify's approval flow.
   */
  static async createSubscription({
    shopDomainOrId,
    plan,
    returnUrl,
    isTest = process.env.NODE_ENV !== "production",
    explicitAccessToken,
  }: {
    shopDomainOrId: string;
    plan: string;
    returnUrl?: string;
    isTest?: boolean;
    explicitAccessToken?: string;
  }): Promise<{
    confirmationUrl: string;
    appSubscriptionId?: string | null;
    plan: PlanTier;
    price: number;
    billingAuthority: "SHOPIFY";
  }> {
    const shop = await this.resolveShopRecord(shopDomainOrId);
    if (!shop) {
      throw new Error(`Shop not found for identifier: ${shopDomainOrId}`);
    }

    // Server-side authoritative plan mapping from dynamic database plan_configs
    const normalizedPlan = (plan || "").toUpperCase();
    const { getPlanByIdOrKey } = await import("./plan-config.server");
    const dbPlan = await getPlanByIdOrKey(normalizedPlan);
    const planConfig = dbPlan || (PLAN_CONFIGS as any)[normalizedPlan] || PLAN_CONFIGS.STARTER;
    const price = Number(planConfig.price);
    const planDisplayName = planConfig.displayName || normalizedPlan;

    if (price <= 0 && normalizedPlan !== "STARTER" && normalizedPlan !== "PRO") {
      throw new Error(`Invalid plan for subscription creation: '${plan}'. Only paid plans can be subscribed.`);
    }

    const planTier: PlanTier = (["FREE", "STARTER", "PRO", "GROWTH"].includes(normalizedPlan) ? normalizedPlan : "STARTER") as PlanTier;

    const baseUrl = process.env.SHOPIFY_APP_URL || "https://portal.webiletechnologies.com";
    const callbackUrl = returnUrl || `${baseUrl}/app/billing?sync=true&plan=${planTier}`;

    // 1. Attempt official Shopify Admin GraphQL mutation appSubscriptionCreate
    let confirmationUrl: string | null = null;
    let appSubscriptionId: string | null = null;

    const { getValidAdminAccessToken } = await import("./shop.server");
    let accessToken = await getValidAdminAccessToken(shop);

    if (explicitAccessToken && !explicitAccessToken.startsWith("shpss_sample_token")) {
      if (explicitAccessToken.startsWith("shpat_") || explicitAccessToken.startsWith("shpua_") || explicitAccessToken.startsWith("shpca_")) {
        accessToken = explicitAccessToken;
      } else {
        try {
          const decrypted = decryptToken(explicitAccessToken);
          if (decrypted && !decrypted.startsWith("shpss_sample_token")) {
            accessToken = decrypted;
          }
        } catch {
          accessToken = explicitAccessToken;
        }
      }
    }

    if (!accessToken) {
      const envToken = process.env.SHOPIFY_ADMIN_ACCESS_TOKEN || process.env.SHOPIFY_ACCESS_TOKEN || process.env.DEFAULT_STORE_ACCESS_TOKEN;
      if (envToken && (envToken.startsWith("shpat_") || envToken.startsWith("shpua_") || envToken.length > 20)) {
        accessToken = envToken;
      }
    }

    const isOneTimePlan = dbPlan?.billingInterval === "ONE_TIME" || dbPlan?.billingType === "ONE_TIME";
    const isTestCharge = isTest !== undefined ? isTest : (process.env.NODE_ENV !== "production" || process.env.SHOPIFY_BILLING_TEST === "true");

    if (accessToken) {
      try {
        let mutation = "";
        let variables: any = {};

        if (isOneTimePlan) {
          mutation = `
            mutation AppPurchaseOneTimeCreate(
              $name: String!
              $price: MoneyInput!
              $returnUrl: URL!
              $test: Boolean
            ) {
              appPurchaseOneTimeCreate(
                name: $name
                price: $price
                returnUrl: $returnUrl
                test: $test
              ) {
                userErrors {
                  field
                  message
                }
                confirmationUrl
                appPurchaseOneTime {
                  id
                  status
                  name
                }
              }
            }
          `;
          variables = {
            name: `CommerceBot AI ${planDisplayName} Plan`,
            returnUrl: callbackUrl,
            test: isTestCharge,
            price: {
              amount: price,
              currencyCode: "USD",
            },
          };
        } else {
          mutation = `
            mutation AppSubscriptionCreate(
              $name: String!
              $returnUrl: URL!
              $lineItems: [AppSubscriptionLineItemInput!]!
              $test: Boolean
              $replacementBehavior: AppSubscriptionReplacementBehavior
            ) {
              appSubscriptionCreate(
                name: $name
                returnUrl: $returnUrl
                lineItems: $lineItems
                test: $test
                replacementBehavior: $replacementBehavior
              ) {
                userErrors {
                  field
                  message
                }
                confirmationUrl
                appSubscription {
                  id
                  status
                  name
                }
              }
            }
          `;
          variables = {
            name: `CommerceBot AI ${planDisplayName} Plan`,
            returnUrl: callbackUrl,
            test: isTestCharge,
            replacementBehavior: "APPLY_IMMEDIATELY",
            lineItems: [
              {
                plan: {
                  appRecurringPricingDetails: {
                    price: {
                      amount: price,
                      currencyCode: "USD",
                    },
                    interval: dbPlan?.billingInterval === "ANNUAL" ? "ANNUAL" : "EVERY_30_DAYS",
                  },
                },
              },
            ],
          };
        }

        const targetShopDomain = shop.shopifyDomain.includes(".") ? shop.shopifyDomain : `${shop.shopifyDomain}.myshopify.com`;
        let response = await fetch(`https://${targetShopDomain}/admin/api/2025-01/graphql.json`, {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            "X-Shopify-Access-Token": accessToken,
          },
          body: JSON.stringify({ query: mutation, variables }),
        });

        if (!response.ok) {
          const text = await response.text();
          if (response.status === 403 && text.includes("Non-expiring access tokens are no longer accepted")) {
            logger.info("Shopify rejected non-expiring token in createSubscription. Attempting automatic token exchange migration...", { shop: targetShopDomain });
            const { forceMigrateToken } = await import("./shop.server");
            const freshToken = await forceMigrateToken(targetShopDomain, accessToken, shop.scopes);
            if (freshToken) {
              accessToken = freshToken;
              response = await fetch(`https://${targetShopDomain}/admin/api/2025-01/graphql.json`, {
                method: "POST",
                headers: {
                  "Content-Type": "application/json",
                  "X-Shopify-Access-Token": accessToken,
                },
                body: JSON.stringify({ query: mutation, variables }),
              });
            } else {
              throw new Error("Shopify requires re-authentication: non-expiring access tokens are deprecated. Please click 'Re-authenticate with Shopify' above.");
            }
          } else {
            logger.warn(`Shopify Admin GraphQL ${isOneTimePlan ? "appPurchaseOneTimeCreate" : "appSubscriptionCreate"} HTTP error`, {
              status: response.status,
              body: text,
              shop: shop.shopifyDomain,
            });
            throw new Error(`Shopify API error HTTP ${response.status}: ${text}`);
          }
        }

        if (response.ok) {
          const result = await response.json();
          const subData = isOneTimePlan ? result?.data?.appPurchaseOneTimeCreate : result?.data?.appSubscriptionCreate;
          if (subData?.confirmationUrl) {
            confirmationUrl = subData.confirmationUrl;
            appSubscriptionId = (isOneTimePlan ? subData.appPurchaseOneTime?.id : subData.appSubscription?.id) || null;
            logger.info(`Shopify ${isOneTimePlan ? "appPurchaseOneTimeCreate" : "appSubscriptionCreate"} succeeded`, {
              confirmationUrl,
              appSubscriptionId,
              shop: shop.shopifyDomain,
            });
          } else if (subData?.userErrors && subData.userErrors.length > 0) {
            const msg = subData.userErrors.map((e: any) => `${e.field ? e.field.join(".") + ": " : ""}${e.message}`).join("; ");
            logger.warn(`Shopify ${isOneTimePlan ? "appPurchaseOneTimeCreate" : "appSubscriptionCreate"} returned userErrors`, {
              errors: subData.userErrors,
              shop: shop.shopifyDomain,
            });
            throw new Error(`Shopify Billing Error: ${msg}`);
          } else if (result?.errors && result.errors.length > 0) {
            const msg = result.errors.map((e: any) => e.message).join("; ");
            logger.warn("Shopify GraphQL errors", { errors: result.errors, shop: shop.shopifyDomain });
            throw new Error(`Shopify GraphQL Error: ${msg}`);
          }
        }
      } catch (err: any) {
        logger.warn("Shopify Admin GraphQL appSubscriptionCreate error", {
          err: err?.message,
          shop: shop.shopifyDomain,
        });
        throw err;
      }
    } else {
      logger.warn("No active access token found for shop GraphQL billing creation", { shop: shop.shopifyDomain });
      throw new Error(`No active access token found for ${shop.shopifyDomain}. Please reinstall or re-open the app from Shopify Admin.`);
    }

    if (!confirmationUrl) {
      throw new Error(`Failed to generate Shopify charge confirmation URL for ${shop.shopifyDomain}. Please verify app permissions.`);
    }

    return {
      confirmationUrl,
      appSubscriptionId,
      plan: planTier,
      price,
      billingAuthority: "SHOPIFY",
    };
  }

  /**
   * Cancels any active Shopify App Subscription and reverts local plan to FREE.
   */
  static async cancelSubscription(shopDomainOrId: string): Promise<void> {
    const shop = await this.resolveShopRecord(shopDomainOrId);
    if (!shop) return;

    try {
      const { getValidAdminAccessToken } = await import("./shop.server");
      let accessToken = await getValidAdminAccessToken(shop);
      if (!accessToken) {
        const rawToken = shop.accessToken ? shop.accessToken.trim() : "";
        if (rawToken) {
          try {
            const decrypted = decryptToken(rawToken);
            if (decrypted && !decrypted.startsWith("shpss_sample_token")) {
              accessToken = decrypted;
            }
          } catch {
            if (rawToken.startsWith("shpat_") || rawToken.startsWith("shpua_")) {
              accessToken = rawToken;
            }
          }
        }
      }

      const activeSub = await prisma.subscription.findFirst({
        where: { shopId: shop.id, status: "ACTIVE" },
        orderBy: { createdAt: "desc" },
      });

      if (accessToken && activeSub?.shopifySubscriptionId) {
        const mutation = `
          mutation AppSubscriptionCancel($id: ID!) {
            appSubscriptionCancel(id: $id) {
              appSubscription {
                id
                status
              }
              userErrors {
                field
                message
              }
            }
          }
        `;
        await fetch(`https://${shop.shopifyDomain}/admin/api/2025-01/graphql.json`, {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            "X-Shopify-Access-Token": accessToken,
          },
          body: JSON.stringify({
            query: mutation,
            variables: { id: activeSub.shopifySubscriptionId },
          }),
        }).catch(() => null);
      }
    } catch (e: any) {
      logger.warn("Error calling Shopify appSubscriptionCancel", { error: e.message });
    }

    await prisma.shop.update({
      where: { id: shop.id },
      data: {
        activePlan: "FREE",
        planHandle: "free",
        subscriptionStatus: "ACTIVE",
        cancelAtEndOfCycle: false,
      },
    });

    await prisma.subscription.updateMany({
      where: { shopId: shop.id },
      data: {
        plan: "FREE",
        planHandle: "free",
        status: "ACTIVE",
        price: 0,
      },
    });
  }

  /**
   * Resolves a Shop record from DB by domain or internal ID.
   */
  private static async resolveShopRecord(shopDomainOrId: string) {
    const input = (shopDomainOrId || "").trim();
    if (!input) return null;

    if (input.includes(".")) {
      const normalizedDomain = input.toLowerCase().replace(/^https?:\/\//, "").replace(/\/.*$/, "");
      return prisma.shop.findUnique({
        where: { shopifyDomain: normalizedDomain },
      });
    }

    return prisma.shop.findUnique({
      where: { id: input },
    });
  }

  /**
   * Queries Shopify Admin GraphQL activeSubscriptions and synchronizes it into our database.
   * Preserves local activePlan when remote Shopify subscription is not active.
   */
  static async syncSubscription(shopDomainOrId: string): Promise<CurrentPlanInfo> {
    const shop = await this.resolveShopRecord(shopDomainOrId);
    if (!shop) {
      throw new Error(`Shop not found for identifier: ${shopDomainOrId}`);
    }

    let resolvedState: ResolvedSubscriptionState | null = null;
    let lookupError: string | null = null;

    // 1. Check Shopify Admin GraphQL currentAppInstallation.activeSubscriptions
    try {
      const { getValidAdminAccessToken, forceMigrateToken } = await import("./shop.server");
      let accessToken = await getValidAdminAccessToken(shop);

      if (!accessToken) {
        const envToken = process.env.SHOPIFY_ADMIN_ACCESS_TOKEN || process.env.SHOPIFY_ACCESS_TOKEN || process.env.DEFAULT_STORE_ACCESS_TOKEN;
        if (envToken && (envToken.startsWith("shpat_") || envToken.startsWith("shpua_") || envToken.length > 20)) {
          accessToken = envToken;
        }
      }

      if (accessToken) {
        const query = `
          query GetActiveSubscriptions {
            currentAppInstallation {
              activeSubscriptions {
                id
                name
                status
                currentPeriodEnd
                test
                lineItems {
                  plan {
                    pricingDetails {
                      ... on AppRecurringPricing {
                        price {
                          amount
                          currencyCode
                        }
                        interval
                      }
                    }
                  }
                }
              }
              oneTimePurchases(first: 5, sortKey: CREATED_AT, reverse: true) {
                edges {
                  node {
                    id
                    name
                    status
                    test
                    price {
                      amount
                      currencyCode
                    }
                  }
                }
              }
            }
          }
        `;

        let response = await fetch(`https://${shop.shopifyDomain}/admin/api/2025-01/graphql.json`, {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            "X-Shopify-Access-Token": accessToken,
          },
          body: JSON.stringify({ query }),
        });

        if (!response.ok) {
          const text = await response.text();
          if (response.status === 403 && text.includes("Non-expiring access tokens are no longer accepted")) {
            logger.info("Shopify rejected non-expiring token in syncSubscription. Attempting automatic token exchange migration...", { shop: shop.shopifyDomain });
            const freshToken = await forceMigrateToken(shop.shopifyDomain, accessToken, shop.scopes);
            if (freshToken) {
              accessToken = freshToken;
              response = await fetch(`https://${shop.shopifyDomain}/admin/api/2025-01/graphql.json`, {
                method: "POST",
                headers: {
                  "Content-Type": "application/json",
                  "X-Shopify-Access-Token": accessToken,
                },
                body: JSON.stringify({ query }),
              });
            }
          }
        }

        if (response.ok) {
          const json = await response.json();
          const activeSubs = json?.data?.currentAppInstallation?.activeSubscriptions || [];
          const oneTimeEdges = json?.data?.currentAppInstallation?.oneTimePurchases?.edges || [];
          const activeOneTimes = oneTimeEdges
            .map((e: any) => e?.node)
            .filter((n: any) => n && n.status === "ACTIVE");

          let dbPlans: any[] = [];
          try {
            const { getActivePlans } = await import("./plan-config.server");
            dbPlans = await getActivePlans();
          } catch {}

          if (activeSubs.length > 0) {
            const activeSub = activeSubs[0];
            const nameLower = (activeSub.name || "").toLowerCase();
            
            // Match against dynamic DB plans first
            const matchedDbPlan = dbPlans.find((p) => 
              nameLower.includes(p.planKey.toLowerCase()) || 
              nameLower.includes(p.displayName.toLowerCase())
            );

            let planTier: PlanTier = "STARTER";
            if (matchedDbPlan) {
              planTier = (matchedDbPlan.planKey === "PRO" || matchedDbPlan.planKey === "GROWTH") ? matchedDbPlan.planKey : "STARTER";
            } else if (nameLower.includes("pro") || nameLower.includes("growth")) {
              planTier = "PRO";
            }

            const lineItem = activeSub.lineItems?.[0]?.plan?.pricingDetails;
            const price = lineItem?.price?.amount 
              ? Number(lineItem.price.amount) 
              : (matchedDbPlan?.price !== undefined ? Number(matchedDbPlan.price) : (planTier === "PRO" ? 79 : 29));
            const cycleEnd = activeSub.currentPeriodEnd ? new Date(activeSub.currentPeriodEnd) : null;

            resolvedState = {
              plan: planTier,
              status: "ACTIVE",
              planHandle: (matchedDbPlan?.planKey || planTier).toLowerCase(),
              displayName: matchedDbPlan?.displayName || activeSub.name || PLAN_CONFIGS[planTier]?.displayName || planTier,
              price,
              currency: lineItem?.price?.currencyCode || "USD",
              billingPeriod: lineItem?.interval === "ANNUAL" ? "ANNUAL" : "EVERY_30_DAYS",
              isTrial: false,
              trialEndsAt: null,
              cancelAtEndOfCycle: false,
              currentBillingCycleStart: new Date(),
              currentBillingCycleEnd: cycleEnd,
              shopifyShopId: shop.shopifyShopId,
              shopifyAppId: activeSub.id,
              rawSubscription: null,
            };
            logger.info(`Synced active Shopify Admin subscription: ${planTier} (${activeSub.id}) for ${shop.shopifyDomain}`);
          } else if (activeOneTimes.length > 0) {
            const activePurchase = activeOneTimes[0];
            const nameLower = (activePurchase.name || "").toLowerCase();

            const matchedDbPlan = dbPlans.find((p) => 
              p.billingInterval === "ONE_TIME" ||
              nameLower.includes(p.planKey.toLowerCase()) || 
              nameLower.includes(p.displayName.toLowerCase())
            );

            const planTier: PlanTier = (nameLower.includes("pro") || matchedDbPlan?.planKey === "PRO") ? "PRO" : "STARTER";
            const price = activePurchase.price?.amount 
              ? Number(activePurchase.price.amount) 
              : (matchedDbPlan?.price !== undefined ? Number(matchedDbPlan.price) : 29);

            resolvedState = {
              plan: planTier,
              status: "ACTIVE",
              planHandle: (matchedDbPlan?.planKey || planTier).toLowerCase(),
              displayName: matchedDbPlan?.displayName || activePurchase.name || PLAN_CONFIGS[planTier]?.displayName || planTier,
              price,
              currency: activePurchase.price?.currencyCode || "USD",
              billingPeriod: "ONE_TIME",
              isTrial: false,
              trialEndsAt: null,
              cancelAtEndOfCycle: false,
              currentBillingCycleStart: new Date(),
              currentBillingCycleEnd: null,
              shopifyShopId: shop.shopifyShopId,
              shopifyAppId: activePurchase.id,
              rawSubscription: null,
            };
            logger.info(`Synced active Shopify Admin one-time purchase: ${planTier} (${activePurchase.id}) for ${shop.shopifyDomain}`);
          }
        }
      }
    } catch (adminErr: any) {
      logger.warn("Admin GraphQL subscription lookup warning", { error: adminErr.message });
    }

    // 2. Partner API fallback if shopifyShopId exists
    if (!resolvedState && shop.shopifyShopId) {
      try {
        const partnerRes = await queryPartnerActiveSubscription({
          shopId: shop.shopifyShopId,
          appId: shop.shopifyAppId || process.env.SHOPIFY_APP_ID,
        });

        if (partnerRes.data?.activeSubscription) {
          resolvedState = mapActiveSubscriptionToPlan(partnerRes.data.activeSubscription, shop.shopifyShopId);
        }
      } catch (partnerErr: any) {
        lookupError = partnerErr.message;
      }
    }

    // 3. If no remote Shopify subscription exists, PRESERVE local DB activePlan!
    // Never arbitrarily overwrite the store's current active plan to FREE!
    if (!resolvedState) {
      const currentPlan: PlanTier = (shop.activePlan as PlanTier) || "FREE";
      const planConfig = PLAN_CONFIGS[currentPlan] || PLAN_CONFIGS.FREE;
      const isTrial = Boolean(shop.trialEndsAt && new Date(shop.trialEndsAt) > new Date());

      resolvedState = {
        plan: currentPlan,
        status: shop.subscriptionStatus || "ACTIVE",
        planHandle: shop.planHandle || currentPlan.toLowerCase(),
        displayName: planConfig.displayName,
        price: planConfig.price,
        currency: "USD",
        billingPeriod: shop.billingPeriod || "EVERY_30_DAYS",
        isTrial,
        trialEndsAt: shop.trialEndsAt,
        cancelAtEndOfCycle: shop.cancelAtEndOfCycle,
        currentBillingCycleStart: shop.currentBillingCycleStart,
        currentBillingCycleEnd: shop.currentBillingCycleEnd,
        shopifyShopId: shop.shopifyShopId,
        shopifyAppId: shop.shopifyAppId,
        rawSubscription: null,
        lookupError,
      };
    }

    const now = new Date();
    const cycleEnd = resolvedState.currentBillingCycleEnd || new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000);
    const effectivePlan = resolvedState.plan;

    // 4. Synchronize Shop model safely
    try {
      await prisma.shop.update({
        where: { id: shop.id },
        data: {
          activePlan: effectivePlan,
          subscriptionStatus: resolvedState.status,
          planHandle: resolvedState.planHandle,
          billingPeriod: resolvedState.billingPeriod,
          trialEndsAt: resolvedState.trialEndsAt,
          cancelAtEndOfCycle: resolvedState.cancelAtEndOfCycle,
          currentBillingCycleStart: resolvedState.currentBillingCycleStart || now,
          currentBillingCycleEnd: cycleEnd,
          lastSubscriptionSync: now,
        },
      });
    } catch (shopErr: any) {
      logger.warn("Could not update full shop subscription fields, falling back to minimal fields", { error: shopErr?.message });
      try {
        await prisma.shop.updateMany({
          where: { id: shop.id },
          data: {
            activePlan: effectivePlan,
            planHandle: resolvedState.planHandle,
            subscriptionStatus: resolvedState.status,
          } as any,
        });
      } catch {}
    }

    // 5. Synchronize Subscription record safely
    try {
      const existingActiveSub = await prisma.subscription.findFirst({
        where: { shopId: shop.id },
        orderBy: { createdAt: "desc" },
      });

      if (existingActiveSub) {
        await prisma.subscription.update({
          where: { id: existingActiveSub.id },
          data: {
            plan: effectivePlan,
            planHandle: resolvedState.planHandle,
            shopifySubscriptionId: resolvedState.shopifyAppId || existingActiveSub.shopifySubscriptionId,
            status: resolvedState.status,
            trialEndsAt: resolvedState.trialEndsAt,
            cancelAtEndOfCycle: resolvedState.cancelAtEndOfCycle,
            price: effectivePlan !== "FREE" ? resolvedState.price : 0,
            billingInterval: resolvedState.billingPeriod === "ANNUAL" ? "ANNUAL" : "MONTHLY",
            billingPeriodStart: resolvedState.currentBillingCycleStart || now,
            billingPeriodEnd: cycleEnd,
          } as any,
        });
      } else {
        await prisma.subscription.create({
          data: {
            shopId: shop.id,
            plan: effectivePlan,
            planHandle: resolvedState.planHandle,
            shopifySubscriptionId: resolvedState.shopifyAppId,
            status: resolvedState.status,
            trialEndsAt: resolvedState.trialEndsAt,
            cancelAtEndOfCycle: resolvedState.cancelAtEndOfCycle,
            price: effectivePlan !== "FREE" ? resolvedState.price : 0,
            currency: resolvedState.currency || "USD",
            billingInterval: resolvedState.billingPeriod === "ANNUAL" ? "ANNUAL" : "MONTHLY",
            billingPeriodStart: resolvedState.currentBillingCycleStart || now,
            billingPeriodEnd: cycleEnd,
            startedAt: now,
          },
        });
      }
    } catch (subErr: any) {
      logger.warn("Subscription model synchronization warning", { error: subErr?.message });
    }

    return await this.buildPlanInfo(shop.shopifyDomain, shop.id, { ...resolvedState, plan: effectivePlan }, now, lookupError);
  }

  /**
   * Retrieves the current verified subscription for a shop.
   * Auto-syncs if last sync is stale (> 1 hour) or never performed.
   */
  static async getActiveSubscription(shopDomainOrId: string): Promise<CurrentPlanInfo> {
    const shop = await this.resolveShopRecord(shopDomainOrId);
    if (!shop) {
      throw new Error(`Shop record not found: ${shopDomainOrId}`);
    }

    const now = new Date();
    const oneHourAgo = new Date(now.getTime() - 60 * 60 * 1000);

    const s = shop as any;
    // If last sync was within 1 hour, use DB cache; otherwise trigger Partner API sync
    if (s.lastSubscriptionSync && s.lastSubscriptionSync > oneHourAgo) {
      const plan = (s.activePlan || "FREE") as PlanTier;
      const planConfig = PLAN_CONFIGS[plan] || PLAN_CONFIGS.FREE;
      const isTrial = Boolean(s.trialEndsAt && new Date(s.trialEndsAt) > now);

      const resolvedState: ResolvedSubscriptionState = {
        plan,
        status: s.subscriptionStatus || "ACTIVE",
        planHandle: s.planHandle || "free",
        displayName: planConfig.displayName,
        price: planConfig.price,
        currency: "USD",
        billingPeriod: s.billingPeriod || "EVERY_30_DAYS",
        isTrial,
        trialEndsAt: s.trialEndsAt,
        cancelAtEndOfCycle: s.cancelAtEndOfCycle,
        currentBillingCycleStart: s.currentBillingCycleStart,
        currentBillingCycleEnd: s.currentBillingCycleEnd,
        shopifyShopId: s.shopifyShopId,
        shopifyAppId: s.shopifyAppId,
        rawSubscription: null,
      };

      return await this.buildPlanInfo(shop.shopifyDomain, shop.id, resolvedState, s.lastSubscriptionSync);
    }

    // Refresh from Partner API
    return this.syncSubscription(shopDomainOrId);
  }

  /**
   * Returns current plan details for a shop.
   */
  static async getCurrentPlan(shopDomainOrId: string): Promise<CurrentPlanInfo> {
    return this.getActiveSubscription(shopDomainOrId);
  }

  /**
   * Retrieves the current verified subscription record for a shop from local database.
   */
  static async getCurrentSubscription(shopDomainOrId: string) {
    const shop = await this.resolveShopRecord(shopDomainOrId);
    if (!shop) return null;
    return prisma.subscription.findFirst({
      where: { shopId: shop.id },
      orderBy: { createdAt: "desc" },
    });
  }

  /**
   * Server-side verifies and synchronizes the subscription state against Shopify.
   */
  static async verifySubscription(shopDomainOrId: string): Promise<CurrentPlanInfo> {
    return this.syncSubscription(shopDomainOrId);
  }

  /**
   * Authoritatively resolves the effective plan tier (FREE, STARTER, PRO, GROWTH).
   * If the Shopify subscription is not ACTIVE, strictly falls back to FREE.
   */
  static async getEffectivePlan(shopDomainOrId: string): Promise<PlanTier> {
    const planInfo = await this.getActiveSubscription(shopDomainOrId);
    if (!planInfo || planInfo.status !== "ACTIVE") {
      return "FREE";
    }
    return planInfo.plan;
  }

  /**
   * Verifies if a shop satisfies a minimum required plan tier.
   */
  static async hasPlan(shopDomainOrId: string, requiredPlan: PlanTier): Promise<boolean> {
    const planInfo = await this.getCurrentPlan(shopDomainOrId);
    const currentRank = PLAN_HIERARCHY[planInfo.plan] || 1;
    const requiredRank = PLAN_HIERARCHY[requiredPlan] || 1;
    return currentRank >= requiredRank;
  }

  /**
   * Verifies if a shop has access to a specific feature key.
   */
  static async hasFeature(shopDomainOrId: string, feature: FeatureKey): Promise<boolean> {
    const planInfo = await this.getCurrentPlan(shopDomainOrId);
    return canUseFeature(planInfo.plan, feature);
  }

  /**
   * Asserts feature access or throws 403 response.
   */
  static async assertFeatureAccess(shopDomainOrId: string, feature: FeatureKey, customMessage?: string): Promise<void> {
    const planInfo = await this.getCurrentPlan(shopDomainOrId);
    if (!canUseFeature(planInfo.plan, feature)) {
      const isAIFeature = feature.startsWith("ai.") || feature === "openai";
      const requiredPlan = isAIFeature ? "Pro" : "Starter";
      const pricingUrl = this.getPricingUrl(planInfo.shopDomain);
      const message =
        customMessage ||
        `Feature '${feature}' requires the ${requiredPlan} plan. Your current plan is ${planInfo.displayName}. Please upgrade to access this feature: ${pricingUrl}`;

      const err: any = new Error(message);
      err.statusCode = 403;
      err.code = "FEATURE_NOT_AVAILABLE";
      err.pricingUrl = pricingUrl;
      throw err;
    }
  }

  /**
   * Builds standardized CurrentPlanInfo DTO with dynamic DB values.
   */
  private static async buildPlanInfo(
    shopDomain: string,
    shopId: string,
    state: ResolvedSubscriptionState,
    lastSync?: Date | null,
    lookupError?: string | null
  ): Promise<CurrentPlanInfo> {
    let dbPlan: any = null;
    try {
      const { getPlanByIdOrKey } = await import("./plan-config.server");
      dbPlan = await getPlanByIdOrKey(state.plan);
    } catch {}

    const planConfig = dbPlan || PLAN_CONFIGS[state.plan] || PLAN_CONFIGS.FREE;

    // Determine statusState
    let statusState: BillingStatusState = "FREE";
    if (lookupError) {
      statusState = "SUBSCRIPTION_LOOKUP_ERROR";
    } else if (state.isTrial) {
      statusState = "TRIAL";
    } else if (state.cancelAtEndOfCycle) {
      statusState = "CANCELLED_AT_END";
    } else if (state.plan === "PRO") {
      statusState = "PRO";
    } else if (state.plan === "STARTER") {
      statusState = "STARTER";
    } else {
      statusState = "FREE";
    }

    return {
      shopDomain,
      shopId,
      shopifyShopId: state.shopifyShopId,
      shopifyAppId: state.shopifyAppId,
      plan: state.plan,
      planHandle: state.planHandle,
      displayName: dbPlan?.displayName || state.displayName || planConfig.displayName,
      price: dbPlan?.price !== undefined ? Number(dbPlan.price) : (state.price !== undefined ? Number(state.price) : planConfig.price),
      currency: state.currency || "USD",
      billingPeriod: state.billingPeriod,
      status: state.status,
      statusState,
      isTrial: state.isTrial,
      trialEndsAt: state.trialEndsAt,
      cancelAtEndOfCycle: state.cancelAtEndOfCycle,
      currentBillingCycleStart: state.currentBillingCycleStart,
      currentBillingCycleEnd: state.currentBillingCycleEnd,
      lastSubscriptionSync: lastSync || null,
      pricingPlansUrl: this.getPricingUrl(shopDomain),
      description: dbPlan?.description || planConfig.description || "",
      features: (dbPlan?.features && dbPlan.features.length > 0) ? dbPlan.features : planConfig.features,
    };
  }
}

/**
 * Backward compatible helper for existing imports.
 */
export async function ensureActiveSubscription(shopId: string) {
  const planInfo = await BillingService.getActiveSubscription(shopId);
  return prisma.subscription.findFirst({
    where: { shopId: planInfo.shopId, status: "ACTIVE" },
    orderBy: { createdAt: "desc" },
  });
}

/**
 * Backward compatible usage check (No artificial 25k quotas - BYOK for Pro).
 */
export async function checkUsageLimit(shopId: string) {
  const planInfo = await BillingService.getActiveSubscription(shopId);
  const hasAI = canUseFeature(planInfo.plan, "openai");

  return {
    limitReached: false,
    isAIApplicable: hasAI,
    currentUsage: 0,
    monthlyLimit: null,
    remainingUsage: null,
    percentageUsed: 0,
    plan: planInfo.plan,
    billingPeriodEnd: planInfo.currentBillingCycleEnd,
    subscriptionId: planInfo.shopId,
    pricingUrl: planInfo.pricingPlansUrl,
  };
}

/**
 * Backward compatible incrementUsage stub (No usage quotas imposed).
 */
export async function incrementUsage(shopId: string) {
  return ensureActiveSubscription(shopId);
}

/**
 * Shopify-authoritative billing service alias.
 */
export const ShopifyBillingService = BillingService;

