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

/**
 * Get active subscription for a user
 * Phase 4: Billing
 */
export const getSubscription = query({
  args: { userId: v.string() },
  handler: async (ctx, args) => {
    // Returns ANY subscription for this userId regardless of status
    return await ctx.db
      .query("subscriptions")
      .withIndex("by_userId", (q) => q.eq("userId", args.userId))
      .first();
  },
});

/**
 * Find subscription by trying multiple userId formats.
 * Solves the userId mismatch: subscription may have been written with
 * appUserId, prismaId, or Convex _id — this tries all three.
 */
export const getSubscriptionByAnyUserId = query({
  args: {
    prismaId: v.optional(v.string()),
    appUserId: v.optional(v.string()),
    convexId: v.optional(v.string()),
  },
  handler: async (ctx, args) => {
    const candidates = [
      args.prismaId,
      args.appUserId,
      args.convexId,
    ].filter((id): id is string => Boolean(id));

    for (const userId of candidates) {
      const sub = await ctx.db
        .query("subscriptions")
        .withIndex("by_userId", (q) => q.eq("userId", userId))
        .filter((q) =>
          q.or(
            q.eq(q.field("status"), "active"),
            q.eq(q.field("status"), "trialing"),
          ),
        )
        .first();
      if (sub) return sub;
    }

    // If no active/trialing found, try any status as last resort
    for (const userId of candidates) {
      const sub = await ctx.db
        .query("subscriptions")
        .withIndex("by_userId", (q) => q.eq("userId", userId))
        .first();
      if (sub) return sub;
    }

    return null;
  },
});

/**
 * Get subscription by Stripe subscription ID
 * Used by Stripe webhook to look up existing subscriptions for updates
 */
export const getByStripeSubscriptionId = query({
  args: { stripeSubscriptionId: v.string() },
  handler: async (ctx, args) => {
    return await ctx.db
      .query("subscriptions")
      .withIndex("by_stripeSubscriptionId", (q) =>
        q.eq("stripeSubscriptionId", args.stripeSubscriptionId),
      )
      .first();
  },
});

/**
 * Get subscription by Stripe customer ID
 * Used by Stripe webhook (payment_intent.succeeded) to find userId from customerId
 */
export const getByStripeCustomerId = query({
  args: { stripeCustomerId: v.string() },
  handler: async (ctx, args) => {
    return await ctx.db
      .query("subscriptions")
      .withIndex("by_stripeCustomerId", (q) =>
        q.eq("stripeCustomerId", args.stripeCustomerId),
      )
      .first();
  },
});

/**
 * Get refund by Stripe refund ID
 * Used by Stripe webhook to look up existing refunds for status updates
 */
export const getByStripeRefundId = query({
  args: { stripeRefundId: v.string() },
  handler: async (ctx, args) => {
    return await ctx.db
      .query("refunds")
      .withIndex("by_stripeRefundId", (q) =>
        q.eq("stripeRefundId", args.stripeRefundId),
      )
      .first();
  },
});

/**
 * Get refund by Stripe charge ID
 * Used by Stripe webhook (charge.refunded) to check if refund exists
 */
export const getByStripeChargeId = query({
  args: { stripeChargeId: v.string() },
  handler: async (ctx, args) => {
    return await ctx.db
      .query("refunds")
      .withIndex("by_stripeChargeId", (q) =>
        q.eq("stripeChargeId", args.stripeChargeId),
      )
      .first();
  },
});

/**
 * Get payment by Stripe payment intent ID
 * Used by Stripe webhook (refund.created) to find customer from payment intent
 */
export const getByStripePaymentIntentId = query({
  args: { stripePaymentIntentId: v.string() },
  handler: async (ctx, args) => {
    return await ctx.db
      .query("payments")
      .withIndex("by_stripePaymentIntentId", (q) =>
        q.eq("stripePaymentIntentId", args.stripePaymentIntentId),
      )
      .first();
  },
});

/**
 * Get billing history for a customer
 * Phase 4: Billing
 */
export const getBillingHistory = query({
  args: {
    customerId: v.string(),
    limit: v.optional(v.number()),
  },
  handler: async (ctx, args) => {
    const limit = args.limit ?? 20;
    return await ctx.db
      .query("billing_history")
      .withIndex("by_customerId", (q) => q.eq("customerId", args.customerId))
      .order("desc")
      .take(limit);
  },
});

/**
 * Alias for getSubscription — used by convex-billing-state.ts and
 * subscription/status route under the name "getActiveSubscription".
 */
export const getActiveSubscription = query({
  args: {
    userId: v.string(),
    prismaId: v.optional(v.string()),
    appUserId: v.optional(v.string()),
  },
  handler: async (ctx, args) => {
    // Try all userId formats to handle write/read mismatch
    const candidates = [args.userId, args.prismaId, args.appUserId].filter(
      (id): id is string => Boolean(id),
    );

    for (const userId of candidates) {
      const sub = await ctx.db
        .query("subscriptions")
        .withIndex("by_userId", (q) => q.eq("userId", userId))
        .filter((q) =>
          q.or(
            q.eq(q.field("status"), "active"),
            q.eq(q.field("status"), "trialing"),
          ),
        )
        .first();
      if (sub) return sub;
    }

    // Fallback: any subscription with these userId formats (handles pending_verification etc.)
    for (const userId of candidates) {
      const sub = await ctx.db
        .query("subscriptions")
        .withIndex("by_userId", (q) => q.eq("userId", userId))
        .first();
      if (sub) return sub;
    }

    return null;
  },
});

/**
 * Get payment records for a customer
 * Phase 4: Billing
 */
export const getPayments = query({
  args: {
    customerId: v.string(),
    status: v.optional(v.string()),
  },
  handler: async (ctx, args) => {
    return await ctx.db
      .query("payments")
      .withIndex("by_customerId", (q) => q.eq("customerId", args.customerId))
      .order("desc")
      .collect();
  },
});
