import { mutation } from "../_generated/server";
import { v } from "convex/values";

/**
 * Create a new subscription record (from Stripe webhook)
 * Phase 4: Billing
 */
export const createSubscription = mutation({
  args: {
    prismaId: v.optional(v.string()),
    userId: v.string(),
    stripeCustomerId: v.string(),
    stripeSubscriptionId: v.string(),
    stripePriceId: v.string(),
    tierId: v.string(),
    status: v.string(),
    billingPeriod: v.string(),
    currentPeriodEnd: v.number(),
    trialEndsAt: v.optional(v.number()),
    paymentMethodId: v.optional(v.string()),
    cardBrand: v.optional(v.string()),
    cardLastFour: v.optional(v.string()),
    setupFeePaid: v.optional(v.union(v.boolean(), v.null())),
    setupFeeAmount: v.optional(v.union(v.number(), v.null())),
    setupFeePaidAt: v.optional(v.union(v.number(), v.null())),
    lastPaymentDate: v.optional(v.union(v.number(), v.null())),
  },
  handler: async (ctx, args) => {
    const now = Date.now();
    const id = await ctx.db.insert("subscriptions", {
      prismaId: args.prismaId,
      userId: args.userId,
      stripeCustomerId: args.stripeCustomerId,
      stripeSubscriptionId: args.stripeSubscriptionId,
      stripePriceId: args.stripePriceId,
      tierId: args.tierId,
      status: args.status,
      billingPeriod: args.billingPeriod,
      currentPeriodEnd: args.currentPeriodEnd,
      trialEndsAt: args.trialEndsAt,
      paymentMethodId: args.paymentMethodId,
      cardBrand: args.cardBrand,
      cardLastFour: args.cardLastFour,
      cancelAtPeriodEnd: false,
      paymentFailureCount: 0,
      setupFeePaid: args.setupFeePaid ?? false,
      setupFeeAmount: args.setupFeeAmount ?? undefined,
      setupFeePaidAt: args.setupFeePaidAt ?? undefined,
      lastPaymentDate: args.lastPaymentDate ?? undefined,
      createdAt: now,
      updatedAt: now,
    });
    return id;
  },
});

/**
 * Update subscription status/details (from Stripe webhook)
 * Phase 4: Billing
 */
export const updateSubscription = mutation({
  args: {
    id: v.id("subscriptions"),
    status: v.optional(v.string()),
    currentPeriodEnd: v.optional(v.number()),
    billingPeriod: v.optional(v.string()),
    cancelAtPeriodEnd: v.optional(v.boolean()),
    cancelledAt: v.optional(v.number()),
    paymentMethodId: v.optional(v.string()),
    cardBrand: v.optional(v.string()),
    cardLastFour: v.optional(v.string()),
    lastPaymentDate: v.optional(v.union(v.number(), v.null())),
    lastPaymentAttempt: v.optional(v.union(v.number(), v.null())),
    paymentFailureCount: v.optional(v.number()),
    stripePriceId: v.optional(v.string()),
    tierId: v.optional(v.string()),
    setupFeePaid: v.optional(v.union(v.boolean(), v.null())),
    setupFeeAmount: v.optional(v.union(v.number(), v.null())),
    setupFeePaidAt: v.optional(v.union(v.number(), v.null())),
    trialEndsAt: v.optional(v.union(v.number(), v.null())),
  },
  handler: async (ctx, args) => {
    const { id, ...fields } = args;
    // Filter out undefined and null values (don't write nulls to Convex)
    const updates: Record<string, unknown> = { updatedAt: Date.now() };
    for (const [key, value] of Object.entries(fields)) {
      if (value !== undefined && value !== null) {
        updates[key] = value;
      }
    }

    await ctx.db.patch(id, updates);
    return id;
  },
});

/**
 * Record a payment in billing history
 * Phase 4: Billing
 */
export const recordPayment = mutation({
  args: {
    customerId: v.string(),
    subscriptionId: v.optional(v.string()),
    invoiceId: v.optional(v.string()),
    event: v.string(),
    amount: v.number(),
    currency: v.string(),
    metadata: v.optional(v.any()),
  },
  handler: async (ctx, args) => {
    const id = await ctx.db.insert("billing_history", {
      customerId: args.customerId,
      subscriptionId: args.subscriptionId,
      invoiceId: args.invoiceId,
      event: args.event,
      amount: args.amount,
      currency: args.currency,
      metadata: args.metadata,
      createdAt: Date.now(),
    });
    return id;
  },
});

/**
 * Update a refund's status (from Stripe webhook)
 * Phase 4: Billing
 */
export const updateRefund = mutation({
  args: {
    id: v.id("refunds"),
    status: v.optional(v.string()),
    failureReason: v.optional(v.string()),
    processedAt: v.optional(v.number()),
  },
  handler: async (ctx, args) => {
    const { id, ...fields } = args;
    const updates: Record<string, unknown> = { updatedAt: Date.now() };
    if (fields.status !== undefined) updates.status = fields.status;
    if (fields.failureReason !== undefined)
      updates.failureReason = fields.failureReason;
    if (fields.processedAt !== undefined)
      updates.processedAt = fields.processedAt;

    await ctx.db.patch(id, updates);
    return id;
  },
});

/**
 * Process a refund
 * Phase 4: Billing
 */
export const processRefund = mutation({
  args: {
    stripeRefundId: v.string(),
    stripePaymentIntentId: v.optional(v.string()),
    customerId: v.string(),
    userId: v.optional(v.string()),
    amount: v.number(),
    currency: v.string(),
    reason: v.optional(v.string()),
  },
  handler: async (ctx, args) => {
    const now = Date.now();
    const id = await ctx.db.insert("refunds", {
      stripeRefundId: args.stripeRefundId,
      stripePaymentIntentId: args.stripePaymentIntentId,
      customerId: args.customerId,
      userId: args.userId,
      amount: args.amount,
      currency: args.currency,
      status: "pending",
      reason: args.reason as
        | "requested_by_customer"
        | "duplicate"
        | "fraudulent"
        | undefined,
      createdAt: now,
      updatedAt: now,
    });
    return id;
  },
});
