import { QueryCtx, MutationCtx } from "../_generated/server";
import { Id, Doc } from "../_generated/dataModel";

export async function recordOrderTimelineEvent(
  ctx: MutationCtx,
  args: {
    orderId: Id<"orders">;
    eventType: string;
    source: string;
    fromStatus?: string;
    toStatus?: string;
    payload?: string;
    userId?: Id<"users">;
  },
): Promise<void> {
  await ctx.db.insert("orderTimelineEvents", {
    ...args,
    createdAt: Date.now(),
  });
}

export async function getOrderWithItems(
  ctx: QueryCtx,
  orderId: Id<"orders">,
) {
  const order = await ctx.db.get(orderId);
  if (!order) return null;

  const items = await ctx.db
    .query("orderItems")
    .withIndex("by_order", (q) => q.eq("orderId", orderId))
    .collect();

  return { ...order, items };
}

/**
 * Determines whether a customer is allowed to cancel a given order.
 *
 * NOTE: Cancellation only updates order status and restores stock.
 * Stripe refund processing is a separate concern handled via the admin
 * dashboard or a future automated flow. This helper does NOT trigger a refund.
 */
export function canCustomerCancel(order: Doc<"orders">): {
  allowed: boolean;
  reason?: string;
} {
  switch (order.status) {
    case "confirmed":
      return { allowed: true };
    case "pending":
      return {
        allowed: false,
        reason: "Order is still awaiting payment confirmation.",
      };
    case "cancelled":
      return { allowed: false, reason: "Order is already cancelled." };
    case "refunded":
      return { allowed: false, reason: "Order has already been refunded." };
    default:
      return {
        allowed: false,
        reason:
          "Order has progressed past the cancellation window. Please contact support.",
      };
  }
}

/**
 * Determines whether a customer is allowed to request a return for a given order.
 *
 * Eligibility: order must be `delivered` (customer has received the goods),
 * return not yet requested, and not already refunded.
 * Returns and cancellations are separate flows — cancellation is only available
 * on `confirmed` orders (before fulfilment begins).
 */
export function canCustomerRequestReturn(order: Doc<"orders">): {
  allowed: boolean;
  reason?: string;
} {
  if (order.status !== "delivered") {
    return {
      allowed: false,
      reason:
        "Returns are only available for delivered orders.",
    };
  }
  if (order.returnRequestedAt) {
    return {
      allowed: false,
      reason: "A return has already been requested for this order.",
    };
  }
  if (order.paymentStatus === "refunded") {
    return { allowed: false, reason: "This order has already been refunded." };
  }
  return { allowed: true };
}

export interface OutOfStockItem {
  variantId: Id<"productVariants">;
  requested: number;
  available: number;
}

/**
 * Check each cart item for sufficient stock. Returns list of out-of-stock entries.
 */
export async function validateCartItems(
  ctx: Pick<QueryCtx, "db">,
  items: { variantId?: Id<"productVariants">; quantity: number }[]
): Promise<OutOfStockItem[]> {
  const outOfStock: OutOfStockItem[] = [];
  for (const item of items) {
    if (!item.variantId) continue;
    const variant = await ctx.db.get(item.variantId);
    if (!variant) {
      outOfStock.push({
        variantId: item.variantId,
        requested: item.quantity,
        available: 0,
      });
      continue;
    }
    if (variant.stockQuantity < item.quantity) {
      outOfStock.push({
        variantId: item.variantId,
        requested: item.quantity,
        available: variant.stockQuantity,
      });
    }
  }
  return outOfStock;
}
