import prisma from "../db.server";
import { PlanTier, SubscriptionStatus } from "@prisma/client";
import { PLAN_CONFIGS } from "../lib/billing-plans";
import { allocateCredits, getAvailableCredits } from "./credit-ledger.server";
import { createNotification } from "./notification.server";

export interface PlanTransitionOptions {
  shopId: string;
  newPlan: PlanTier;
  shopifySubscriptionId?: string;
}

/**
 * Service class / module providing modern Shopify Embedded Billing operations.
 */
export class SubscriptionService {
  /**
   * Retrieves the single currently ACTIVE recurring subscription for a shop.
   * Auto-creates a default FREE active plan if none exists.
   */
  static async getActiveSubscription(shopId: string) {
    const now = new Date();
    let activeSub = await prisma.subscription.findFirst({
      where: { shopId, status: "ACTIVE" },
      orderBy: { createdAt: "desc" },
    });

    // Check if active recurring subscription expired
    if (activeSub && activeSub.billingInterval === "MONTHLY" && activeSub.billingPeriodEnd && now > new Date(activeSub.billingPeriodEnd)) {
      // If recurring subscription expired, mark it expired and fallback to FREE basic one-time
      if (activeSub.plan !== "FREE") {
        await prisma.subscription.update({
          where: { id: activeSub.id },
          data: { status: "EXPIRED", endedAt: now },
        });
        activeSub = null;
      }
    }

    if (!activeSub) {
      const freeConfig = PLAN_CONFIGS.FREE;
      // Perpetual end date for one-time purchase
      const perpetualEnd = new Date(now.getTime() + 3650 * 24 * 60 * 60 * 1000); // 10 years

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

      // Allocate initial free credits if applicable
      try {
        if (freeConfig.monthlyLimit > 0) {
          await allocateCredits({
            shopId,
            sourceType: "MONTHLY_PLAN",
            amount: freeConfig.monthlyLimit,
            sourceId: activeSub.id,
            expiresAt: perpetualEnd,
            idempotencyKey: `sub_free_init_${shopId}`,
          });
        }
      } catch (e) {}
    }

    return activeSub;
  }

  /**
   * Retrieves full immutable subscription purchase history for a shop.
   */
  static async getSubscriptionHistory(shopId: string) {
    return prisma.subscription.findMany({
      where: { shopId },
      orderBy: { createdAt: "desc" },
      include: {
        payments: {
          include: { invoices: true },
          orderBy: { createdAt: "desc" },
        },
      },
    });
  }

  /**
   * Retrieves a specific subscription record by ID with linked payment and invoice.
   */
  static async getSubscriptionById(subscriptionId: string) {
    return prisma.subscription.findUnique({
      where: { id: subscriptionId },
      include: {
        payments: {
          include: { invoices: true },
          orderBy: { createdAt: "desc" },
        },
      },
    });
  }

  /**
   * Returns a unified SaaS platform billing summary for a shop.
   */
  static async getBillingSummary(shopId: string) {
    const activeSub = await this.getActiveSubscription(shopId);
    const history = await this.getSubscriptionHistory(shopId);
    const creditBalance = await getAvailableCredits(shopId);

    const payments = await prisma.payment.findMany({
      where: { shopId },
      orderBy: { createdAt: "desc" },
      include: { invoices: true },
    });

    const lifetimeSpendResult = await prisma.payment.aggregate({
      where: { shopId, status: "SUCCESSFUL" },
      _sum: { amount: true },
    });

    const lifetimeSpend = lifetimeSpendResult._sum.amount || 0;

    const { getPlansDictionary, getPlanByIdOrKey } = await import("./plan-config.server");
    const plansDict = await getPlansDictionary();
    const activePlanConfig = plansDict[activeSub.plan] || PLAN_CONFIGS[activeSub.plan as PlanTier] || PLAN_CONFIGS.FREE;

    return {
      activeSubscription: {
        id: activeSub.id,
        plan: activeSub.plan,
        displayName: activePlanConfig.displayName,
        price: activeSub.price ? parseFloat(activeSub.price.toString()) : activePlanConfig.price,
        currency: activeSub.currency || "USD",
        billingType: activePlanConfig.billingType,
        billingInterval: activeSub.billingInterval || activePlanConfig.billingInterval,
        status: activeSub.status,
        startedAt: activeSub.startedAt,
        currentPeriodStart: activeSub.billingPeriodStart,
        currentPeriodEnd: activeSub.billingPeriodEnd,
        aiMonthlyLimit: activePlanConfig.aiMonthlyLimit,
        monthlyLimit: activePlanConfig.monthlyLimit,
        currentUsage: activePlanConfig.aiMonthlyLimit ? activeSub.currentUsage : 0,
        shopifySubscriptionId: activeSub.shopifySubscriptionId,
      },
      subscriptionHistory: history.map((sub) => {
        const cfg = plansDict[sub.plan] || PLAN_CONFIGS[sub.plan as PlanTier] || PLAN_CONFIGS.FREE;
        return {
          id: sub.id,
          plan: sub.plan,
          displayName: cfg.displayName,
          price: sub.price ? parseFloat(sub.price.toString()) : cfg.price,
          currency: sub.currency,
          billingType: cfg.billingType,
          billingInterval: sub.billingInterval,
          status: sub.status,
          startedAt: sub.startedAt,
          endedAt: sub.endedAt,
          currentPeriodStart: sub.billingPeriodStart,
          currentPeriodEnd: sub.billingPeriodEnd,
          aiMonthlyLimit: cfg.aiMonthlyLimit,
          monthlyLimit: cfg.monthlyLimit,
          currentUsage: sub.currentUsage,
          shopifySubscriptionId: sub.shopifySubscriptionId,
          createdAt: sub.createdAt,
          payments: sub.payments,
        };
      }),
      totalPlansPurchased: history.length,
      creditBalance,
      payments: payments.map((p) => ({
        id: p.id,
        subscriptionId: p.subscriptionId,
        amount: p.amount,
        currency: p.currency,
        status: p.status,
        provider: p.provider,
        providerPaymentId: p.providerPaymentId,
        paidAt: p.paidAt,
        createdAt: p.createdAt,
        invoices: p.invoices,
      })),
      lifetimeSpend,
    };
  }

  /**
   * Alias for transitionSubscriptionPlan for backward compatibility across routes.
   */
  static async changePlan(options: PlanTransitionOptions) {
    return this.transitionSubscriptionPlan(options);
  }

  /**
   * Transitions a shop to a new subscription plan.
   * Preserves all historical records by updating the prior active subscription status to REPLACED.
   */
  static async transitionSubscriptionPlan({
    shopId,
    newPlan,
    shopifySubscriptionId,
  }: PlanTransitionOptions) {
    const now = new Date();
    const { getPlanByIdOrKey } = await import("./plan-config.server");
    const dbPlan = await getPlanByIdOrKey(String(newPlan));
    const planConfig = dbPlan || PLAN_CONFIGS[newPlan] || PLAN_CONFIGS.FREE;
    const isOneTime = planConfig.billingInterval === "ONE_TIME";
    const nextCycleEnd = isOneTime
      ? new Date(now.getTime() + 3650 * 24 * 60 * 60 * 1000)
      : new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000);

    // 1. Mark existing ACTIVE subscription(s) as REPLACED (never delete history)
    await prisma.subscription.updateMany({
      where: { shopId, status: "ACTIVE" },
      data: {
        status: "REPLACED",
        endedAt: now,
      },
    });

    const validPlanTier: PlanTier = ["FREE", "STARTER", "GROWTH", "PRO"].includes(newPlan.toUpperCase())
      ? (newPlan.toUpperCase() as PlanTier)
      : planConfig.price >= 79
      ? "PRO"
      : planConfig.price >= 29
      ? "STARTER"
      : "FREE";

    const officialShopifySubId = shopifySubscriptionId || `gid://shopify/AppSubscription/${Date.now()}`;

    // 2. Create NEW active subscription record
    const newSub = await prisma.subscription.create({
      data: {
        shopId,
        plan: validPlanTier,
        price: planConfig.price,
        currency: "USD",
        billingInterval: planConfig.billingInterval,
        shopifySubscriptionId: officialShopifySubId,
        status: "ACTIVE",
        monthlyLimit: planConfig.monthlyLimit,
        currentUsage: 0,
        startedAt: now,
        billingPeriodStart: now,
        billingPeriodEnd: nextCycleEnd,
      },
    });

    // 3. Update Shop activePlan
    await prisma.shop.update({
      where: { id: shopId },
      data: {
        activePlan: validPlanTier,
        subscriptionStatus: "ACTIVE",
        billingPeriod: planConfig.billingInterval,
        currentBillingCycleStart: now,
        currentBillingCycleEnd: nextCycleEnd,
        lastSubscriptionSync: now,
      },
    });

    // 4. Create Payment & Invoice record strictly attributed to Shopify Billing
    try {
      const payment = await prisma.payment.create({
        data: {
          shopId,
          subscriptionId: newSub.id,
          amount: planConfig.price,
          currency: "USD",
          status: "SUCCESSFUL",
          provider: "shopify",
          providerPaymentId: officialShopifySubId,
          idempotencyKey: `pay_${shopId}_${Date.now()}`,
        },
      });

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

      const planName = planConfig.displayName || (planConfig as any).name || (planConfig as any).planKey || newPlan;

      await prisma.auditLog.create({
        data: {
          shopId,
          action: `${newPlan}_SUBSCRIPTION_ACTIVATED`,
          resource: `Activated ${planName} Plan ($${planConfig.price}.00 USD/mo) via Shopify App Billing`,
          status: "SUCCESSFUL",
          metadata: {
            plan: newPlan,
            price: planConfig.price,
            subscriptionId: newSub.id,
            shopifySubscriptionId: officialShopifySubId,
            billingAuthority: "SHOPIFY",
          },
        },
      });

      await createNotification({
        shopId,
        type: "SUBSCRIPTION_UPDATED",
        title: `Activated ${planName} Plan`,
        message: `Your store subscription was activated for ${planName} via Shopify Billing.`,
      });
    } catch (payErr) {
      console.error("[SubscriptionService] Error logging Shopify payment record:", payErr);
    }

    return newSub;
  }
}
