import dayjs from "dayjs";
import pLimit from "p-limit";
import { razorpay } from "../config/razorpay.ts";
import { executeBulkSubscriptionPaymentProcess } from "../controllers/payments.controller.ts";
import { prisma } from "../config/db.ts";

const PAYMENT_TIMEOUT_MINUTES = 30;
const MAX_CONCURRENT_PAYMENTS = 5;

let isProcessingPayments = false;

const updateTransactionStatus = async (
    id: string,
    status: "FAILED" | "EXPIRED",
    failureReason: string
) => {
    await prisma.transaction.update({
        where: { id },
        data: {
            status,
            failureReason,
        },
    });
};

const processTransaction = async (txn: { id: string; orderId: string | null; }) => {
    if (!txn.orderId) return;

    try {
        console.log(`🔎 Checking Razorpay Order: ${txn.orderId}`);

        const { items = [] } = await razorpay.orders.fetchPayments(txn.orderId);
        const capturedPayment = items.find((payment) => payment.status === "captured");

        if (capturedPayment) {
            console.log(`✅ Payment captured for ${txn.orderId}`);
            await executeBulkSubscriptionPaymentProcess({ orderId: txn.orderId, });
            return;
        }

        const authorizedPayment = items.find((payment) => payment.status === "authorized");

        if (authorizedPayment) {
            console.log(`⌛ Payment authorized but not captured yet: ${txn.orderId}`);
            return;
        }

        const failedPayment = items.find((payment) => payment.status === "failed");

        if (failedPayment) {
            console.log(`❌ Payment failed: ${txn.orderId}`);
            await updateTransactionStatus(txn.id, "FAILED", `Razorpay payment ${failedPayment.status}`);
            return;
        }

        if (items.length === 0) {
            console.log(`⌛ No payment attempts. Expiring ${txn.orderId}`);
            await updateTransactionStatus(txn.id, "EXPIRED", "Checkout session expired or abandoned");
            return;
        }

        console.log(`ℹ️ Payment exists but is in '${items[0].status}' state for ${txn.orderId}`);
    } catch (error) {
        console.error(`❌ Error processing transaction ${txn.id}`, error);

        // Leave it as PENDING.
        // Next cron execution will retry.
    }
};

export const processAbandonedPayments = async () => {
    if (isProcessingPayments) {
        console.log("⚠️ Payment cleanup already running. Skipping...");
        return;
    }

    isProcessingPayments = true;

    try {
        console.log("💳 Running abandoned payment cleanup...");

        const expiredBefore = dayjs().subtract(PAYMENT_TIMEOUT_MINUTES, "minute").toDate();

        const pendingTransactions = await prisma.transaction.findMany({
            where: {
                status: "PENDING",
                orderId: {
                    not: null,
                },
                createdAt: {
                    lt: expiredBefore,
                },
            },
            select: {
                id: true,
                orderId: true,
            },
        });

        console.log(`🔍 [${dayjs().format("YYYY-MM-DD HH:mm:ss")}] Found ${pendingTransactions.length} pending transactions`);

        const limit = pLimit(MAX_CONCURRENT_PAYMENTS);

        await Promise.all(
            pendingTransactions.map((txn) =>
                limit(() => processTransaction(txn))
            )
        );

        console.log("✅ Payment cleanup completed.");
    } catch (error) {
        console.error("❌ Payment cleanup cron error:", error);
    } finally {
        isProcessingPayments = false;
    }
};