import { ShopifyAdminClient } from "../lib/shopify/admin";
import { getTenantByDomain } from "../lib/security/tenant-context";
import prisma from "../db.server";
import { PlanTier } from "@prisma/client";
import { createNotification } from "./notification.server";
import { PLAN_CONFIGS, PlanDetails } from "../lib/billing-plans";
import { allocateCredits } from "./credit-ledger.server";
import { SubscriptionService } from "./subscription.server";
import { processRazorpayTransaction } from "./razorpay.server";

export { PLAN_CONFIGS };
export type { PlanDetails };

export const CREDIT_PACKAGES: Record<string, { id: string; name: string; credits: number; price: number }> = {
  PKG_1000: { id: "PKG_1000", name: "Starter Booster Pack", credits: 1000, price: 10 },
  PKG_5000: { id: "PKG_5000", name: "Growth Booster Pack", credits: 5000, price: 40 },
  PKG_10000: { id: "PKG_10000", name: "Scale Booster Pack", credits: 10000, price: 70 },
};

/**
 * Ensures an active subscription exists for a shop and auto-resets usage if a new billing cycle has started.
 */
export async function ensureActiveSubscription(shopId: string) {
  let activeSub = await prisma.subscription.findFirst({
    where: { shopId, status: "ACTIVE" },
    orderBy: { createdAt: "desc" },
  });

  const now = new Date();

  if (!activeSub) {
    const freeConfig = PLAN_CONFIGS.FREE;
    const perpetualEnd = new Date(now.getTime() + 3650 * 24 * 60 * 60 * 1000);

    activeSub = await prisma.subscription.create({
      data: {
        shopId,
        plan: "FREE",
        status: "ACTIVE",
        price: freeConfig.price,
        currency: "USD",
        billingInterval: freeConfig.billingInterval,
        monthlyLimit: freeConfig.monthlyLimit, // 0 for Free
        currentUsage: 0,
        billingPeriodStart: now,
        billingPeriodEnd: perpetualEnd,
      },
    });

    return activeSub;
  }

  // Automatic Billing Cycle Reset check for RECURRING MONTHLY subscriptions only
  if (activeSub.billingInterval === "MONTHLY" && activeSub.billingPeriodEnd && now > new Date(activeSub.billingPeriodEnd)) {
    const newEnd = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000);
    const planConfig = PLAN_CONFIGS[activeSub.plan as PlanTier] || PLAN_CONFIGS.FREE;

    activeSub = await prisma.subscription.update({
      where: { id: activeSub.id },
      data: {
        currentUsage: 0,
        billingPeriodStart: now,
        billingPeriodEnd: newEnd,
      },
    });

    // Allocate new cycle monthly plan credits if AI applicable
    if (planConfig.aiMonthlyLimit) {
      try {
        await allocateCredits({
          shopId,
          sourceType: "MONTHLY_PLAN",
          amount: planConfig.aiMonthlyLimit,
          sourceId: activeSub.id,
          expiresAt: newEnd,
          idempotencyKey: `sub_renew_${shopId}_${newEnd.toISOString().split("T")[0]}`,
        });
      } catch (e) {}
    }

    try {
      await createNotification({
        shopId,
        type: "SUBSCRIPTION_UPDATED",
        title: "Monthly Usage Limit Reset",
        message: `Your monthly AI usage limit has reset for your new billing cycle.`,
      });
    } catch (e) {
      console.error("[Billing Server] Error creating reset notification:", e);
    }
  }

  return activeSub;
}

/**
 * Checks whether a shop has reached its AI usage limit.
 * Only applicable to plans with aiMonthlyLimit (Pro).
 */
export async function checkUsageLimit(shopId: string) {
  const activeSub = await ensureActiveSubscription(shopId);
  const plan = (activeSub.plan || "FREE") as PlanTier;
  const planConfig = PLAN_CONFIGS[plan] || PLAN_CONFIGS.FREE;

  if (!planConfig.aiMonthlyLimit) {
    // Free & Starter do not have AI access or AI limits
    return {
      limitReached: false,
      isAIApplicable: false,
      currentUsage: 0,
      monthlyLimit: null,
      remainingUsage: null,
      percentageUsed: 0,
      plan,
      billingPeriodEnd: activeSub.billingPeriodEnd,
      subscriptionId: activeSub.id,
    };
  }

  const limitReached = activeSub.currentUsage >= planConfig.aiMonthlyLimit;
  const remainingUsage = Math.max(0, planConfig.aiMonthlyLimit - activeSub.currentUsage);
  const percentageUsed = Math.min(100, Math.round((activeSub.currentUsage / planConfig.aiMonthlyLimit) * 100));

  return {
    limitReached,
    isAIApplicable: true,
    currentUsage: activeSub.currentUsage,
    monthlyLimit: planConfig.aiMonthlyLimit,
    remainingUsage,
    percentageUsed,
    plan,
    billingPeriodEnd: activeSub.billingPeriodEnd,
    subscriptionId: activeSub.id,
  };
}

/**
 * Atomically increments AI usage count only for AI-enabled plans (Pro).
 * Free and Starter plans do not use or track AI usage.
 */
export async function incrementUsage(shopId: string) {
  const activeSub = await ensureActiveSubscription(shopId);
  const plan = (activeSub.plan || "FREE") as PlanTier;
  const planConfig = PLAN_CONFIGS[plan] || PLAN_CONFIGS.FREE;

  if (!planConfig.aiMonthlyLimit) {
    // Do not track AI usage for Free or Starter
    return activeSub;
  }

  const updatedSub = await prisma.subscription.update({
    where: { id: activeSub.id },
    data: { currentUsage: { increment: 1 } },
  });

  if (updatedSub.currentUsage >= planConfig.aiMonthlyLimit) {
    try {
      await createNotification({
        shopId,
        type: "USAGE_LIMIT_WARNING",
        title: "AI Usage Limit Reached",
        message: `Your store reached 100% of its monthly AI limit (${updatedSub.currentUsage}/${planConfig.aiMonthlyLimit} msgs). Upgrade or purchase booster credits to continue using AI features.`,
      });
    } catch (e) {
      console.error("[Billing Server] Error creating limit notification:", e);
    }
  }

  return updatedSub;
}

import { getPlanByIdOrKey, getPlansDictionary } from "./plan-config.server";

export async function createSubscriptionCharge({
  shopDomain,
  plan,
  paymentDetails,
}: {
  shopDomain: string;
  plan: PlanTier | string;
  paymentDetails?: {
    cardName?: string;
    cardNumber?: string;
    cardExpiry?: string;
    cardCvc?: string;
    paymentMethod?: string;
    paymentAmount?: number;
  };
}) {
  const tenant = await getTenantByDomain(shopDomain);
  const dbPlan = await getPlanByIdOrKey(String(plan));
  if (dbPlan && dbPlan.isActive === false) {
    return { success: false, error: `The ${dbPlan.displayName || plan} plan is currently inactive and not available for subscription.` };
  }
  const planConfig = dbPlan || PLAN_CONFIGS[plan as PlanTier] || PLAN_CONFIGS.FREE;
  const now = new Date();
  const nextCycleEnd = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000);

  const rawCard = paymentDetails?.cardNumber || "";
  const cleanCard = rawCard.replace(/[\s-]/g, "");
  const cardName = paymentDetails?.cardName || "";
  const cardExpiry = paymentDetails?.cardExpiry || "";
  const cardCvc = paymentDetails?.cardCvc || "";
  const submittedAmount = paymentDetails?.paymentAmount !== undefined ? paymentDetails.paymentAmount : planConfig.price;

  const maskedCard = cleanCard.length >= 4
    ? `•••• •••• •••• ${cleanCard.slice(-4)}`
    : "•••• •••• •••• 4242";

  // --- STRICT PAYMENT VERIFICATION ---
  if (paymentDetails && paymentDetails.cardNumber) {
    // 1. Verify Payment Amount matches exact Plan Tier price
    if (submittedAmount !== planConfig.price) {
      const failReason = `Payment amount mismatch: Expected $${planConfig.price}.00 USD for ${planConfig.displayName || plan} plan, but received $${submittedAmount}.00 USD.`;
      
      try {
        await prisma.auditLog.create({
          data: {
            shopId: tenant.shopId,
            action: `${plan}_PAYMENT_FAILED`,
            resource: failReason,
            status: "FAILED",
            metadata: { plan, expectedPrice: planConfig.price, submittedAmount, cardName, cardNumber: maskedCard },
          },
        });
      } catch (err) {}

      return { success: false, error: failReason };
    }

    // 2. Verify Cardholder Name
    if (!cardName || cardName.length < 2) {
      const failReason = "Cardholder Name verification failed: Please enter a valid cardholder name.";
      return { success: false, error: failReason };
    }

    // 3. Verify Card Number digits & check for test decline pattern
    if (!cleanCard || cleanCard.length < 13 || cleanCard.length > 19 || !/^\d+$/.test(cleanCard)) {
      const failReason = "Card number verification failed: Invalid credit/debit card number.";
      return { success: false, error: failReason };
    }

    if (cleanCard === "0000000000000000" || cleanCard.startsWith("0000")) {
      const failReason = "Payment declined: Card bank authorization failed. Please try a different card.";
      
      try {
        await prisma.auditLog.create({
          data: {
            shopId: tenant.shopId,
            action: `${plan}_PAYMENT_FAILED`,
            resource: failReason,
            status: "FAILED",
            metadata: { plan, amount: planConfig.price, cardName, cardNumber: maskedCard },
          },
        });
      } catch (err) {}

      return { success: false, error: failReason };
    }

    // 4. Verify Expiration Date format (MM/YY or MM/YYYY)
    if (!cardExpiry || !/^\d{2}\/\d{2,4}$/.test(cardExpiry)) {
      const failReason = "Card expiration verification failed: Use MM/YY format.";
      return { success: false, error: failReason };
    }
  }

  // --- PROCESS TRANSACTION IN RAZORPAY DASHBOARD ---
  const rzpRes = await processRazorpayTransaction({
    amount: planConfig.price,
    currency: "USD",
    receipt: `sub_${plan}_${Date.now()}`,
    notes: {
      shopDomain,
      plan,
      cardName,
    },
    cardDetails: {
      cardName,
      cardNumber: cleanCard,
      cardExpiry,
      cardCvc,
    },
  });

  // --- ACTIVATE SUBSCRIPTION PLAN ON VERIFIED SUCCESS VIA SubscriptionService ---
  const newSub = await SubscriptionService.transitionSubscriptionPlan({
    shopId: tenant.shopId,
    newPlan: plan as PlanTier,
    shopifySubscriptionId: rzpRes.razorpayOrderId || `gid://shopify/AppSubscription/${Date.now()}`,
    paymentDetails: {
      cardName,
      cardNumber: cleanCard,
      cardExpiry,
      cardCvc,
      amount: planConfig.price,
    },
  });

  const billingLabel = planConfig.billingInterval === "ONE_TIME" ? "one-time purchase" : "per month";
  const planDisplayName = planConfig.displayName || (planConfig as any).name || (planConfig as any).planKey || plan;

  try {
    await createNotification({
      shopId: tenant.shopId,
      type: "SUBSCRIPTION_UPDATED",
      title: `Subscribed to ${planDisplayName} Plan`,
      message: `Your store subscription was verified and activated for ${planDisplayName} at $${planConfig.price} (${billingLabel}).`,
    });
  } catch (e) {}

  return {
    success: true,
    message: `Payment verified ($${planConfig.price}.00 USD). Activated ${planDisplayName} Plan!`,
    confirmationUrl: `/app?shop=${shopDomain}&planChanged=${plan}`,
  };
}

/**
 * Purchase additional credit booster package.
 * ADDITIVE RULE: Appends credits to existing balance without replacing or resetting remaining usage.
 */
export async function purchaseCreditPackage({
  shopDomain,
  packageId,
  paymentDetails,
}: {
  shopDomain: string;
  packageId: string;
  paymentDetails?: {
    cardName?: string;
    cardNumber?: string;
    cardExpiry?: string;
    cardCvc?: string;
  };
}) {
  const tenant = await getTenantByDomain(shopDomain);
  const pkg = CREDIT_PACKAGES[packageId] || CREDIT_PACKAGES.PKG_1000;

  const rawCard = paymentDetails?.cardNumber || "";
  const cleanCard = rawCard.replace(/[\s-]/g, "");
  const cardName = paymentDetails?.cardName || "";
  const cardExpiry = paymentDetails?.cardExpiry || "";

  const maskedCard = cleanCard.length >= 4 ? `•••• •••• •••• ${cleanCard.slice(-4)}` : "•••• •••• •••• 4242";

  // Card verification
  if (!cardName || cardName.length < 2) {
    return { success: false, error: "Please enter a valid Cardholder Name." };
  }
  if (!cleanCard || cleanCard.length < 13 || cleanCard.length > 19 || !/^\d+$/.test(cleanCard)) {
    return { success: false, error: "Invalid credit/debit card number." };
  }
  if (cleanCard === "0000000000000000" || cleanCard.startsWith("0000")) {
    return { success: false, error: "Payment declined: Card bank authorization failed." };
  }
  if (!cardExpiry || !/^\d{2}\/\d{2,4}$/.test(cardExpiry)) {
    return { success: false, error: "Invalid expiration date format (use MM/YY)." };
  }

  const idempotencyKey = `credit_pkg_${tenant.shopId}_${packageId}_${Date.now()}`;

  // Process transaction in Razorpay Dashboard
  const rzpRes = await processRazorpayTransaction({
    amount: pkg.price,
    currency: "USD",
    receipt: `credit_${packageId}_${Date.now()}`,
    notes: {
      shopDomain,
      packageId,
      credits: String(pkg.credits),
    },
    cardDetails: {
      cardName,
      cardNumber: cleanCard,
      cardExpiry,
    },
  });

  // 1. Allocate credits to ledger (Additive rule)
  const allocation = await allocateCredits({
    shopId: tenant.shopId,
    sourceType: "ADDITIONAL_PURCHASE",
    amount: pkg.credits,
    sourceId: packageId,
    expiresAt: null, // Non-expiring booster credits
    idempotencyKey,
  });

  // 2. Log Payment & Invoice
  try {
    const payment = await prisma.payment.create({
      data: {
        shopId: tenant.shopId,
        amount: pkg.price,
        currency: "USD",
        status: "SUCCESSFUL",
        provider: "card",
        idempotencyKey,
      },
    });

    await prisma.invoice.create({
      data: {
        shopId: tenant.shopId,
        paymentId: payment.id,
        invoiceNumber: `INV-CRED-${Date.now().toString().slice(-6)}`,
        amount: pkg.price,
        currency: "USD",
        status: "PAID",
      },
    });

    await prisma.auditLog.create({
      data: {
        shopId: tenant.shopId,
        action: "ADDITIONAL_CREDITS_PURCHASED",
        resource: `Purchased +${pkg.credits.toLocaleString()} Credits for $${pkg.price}.00 USD | Card: ${maskedCard}`,
        status: "SUCCESSFUL",
        metadata: {
          packageId,
          credits: pkg.credits,
          amount: pkg.price,
          cardNumber: maskedCard,
          cardName,
        },
      },
    });

    await createNotification({
      shopId: tenant.shopId,
      type: "CREDITS_PURCHASED",
      title: `Purchased +${pkg.credits.toLocaleString()} Credits`,
      message: `Your credit purchase of +${pkg.credits.toLocaleString()} credits ($${pkg.price}) was successful and added to your available balance.`,
    });
  } catch (err) {
    console.error("[Billing Server] Error logging credit package purchase:", err);
  }

  return {
    success: true,
    message: `Successfully purchased +${pkg.credits.toLocaleString()} credits ($${pkg.price}.00 USD)! Added to available balance.`,
    creditsAdded: pkg.credits,
    allocationId: allocation.id,
  };
}
