"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.metadata = void 0;
const db_1 = require("@b/db");
const error_1 = require("@b/utils/error");
const json_parser_1 = require("@b/api/(ext)/p2p/utils/json-parser");
const sequelize_1 = require("sequelize");
const utils_1 = require("@b/api/finance/currency/utils"); // <-- path as in your project
exports.metadata = {
    summary: "Submit Guided Matching Criteria",
    description: "Finds matching offers based on guided matching criteria provided by the authenticated user.",
    operationId: "submitP2PGuidedMatching",
    tags: ["P2P", "Guided Matching"],
    requiresAuth: true,
    logModule: "P2P_MATCHING",
    logTitle: "Submit guided matching criteria",
    requestBody: {
        description: "Guided matching criteria",
        required: true,
        content: {
            "application/json": {
                schema: {
                    type: "object",
                    properties: {
                        tradeType: { type: "string", enum: ["buy", "sell"] },
                        cryptocurrency: { type: "string" },
                        amount: { type: "string" },
                        paymentMethods: { type: "array", items: { type: "string" } },
                        pricePreference: { type: "string" },
                        traderPreference: { type: "string" },
                        location: { type: "string" },
                    },
                    required: [
                        "tradeType",
                        "cryptocurrency",
                        "amount",
                        "paymentMethods",
                        "pricePreference",
                        "traderPreference",
                        "location",
                    ],
                },
            },
        },
    },
    responses: {
        200: { description: "Matching results retrieved successfully." },
        401: { description: "Unauthorized." },
        500: { description: "Internal Server Error." },
    },
};
// Smart Score Calculation Helper
const calculateMatchScore = ({ price, bestPrice, completionRate, verified, methodOverlap, }) => {
    let score = 0;
    score +=
        bestPrice && price
            ? (1 - Math.abs((price - bestPrice) / bestPrice)) * 40
            : 0;
    score += (completionRate || 0) * 0.3;
    score += verified ? 20 : 0;
    score += methodOverlap ? 10 : 0;
    return Math.round(score);
};
// Utility: fetch market price based on wallet type
async function getMarketPrice(currency, walletType) {
    switch (walletType) {
        case "FIAT":
            return (0, utils_1.getFiatPriceInUSD)(currency);
        case "SPOT":
            return (0, utils_1.getSpotPriceInUSD)(currency);
        case "ECO":
            return (0, utils_1.getEcoPriceInUSD)(currency);
        default:
            return null;
    }
}
exports.default = async (data) => {
    const { body, user, ctx } = data;
    if (!(user === null || user === void 0 ? void 0 : user.id))
        throw (0, error_1.createError)({ statusCode: 401, message: "Unauthorized" });
    ctx === null || ctx === void 0 ? void 0 : ctx.step("Parsing matching criteria");
    try {
        // Parse amount as number
        const amount = parseFloat(body.amount) || 0;
        ctx === null || ctx === void 0 ? void 0 : ctx.step(`Finding ${body.tradeType} offers for ${body.cryptocurrency}`);
        // Fetch all eligible offers in one query, with associated user and payment methods
        const offers = await db_1.models.p2pOffer.findAll({
            where: {
                currency: body.cryptocurrency,
                type: body.tradeType.toUpperCase(),
                status: "ACTIVE",
                ...(amount && {
                    "amountConfig.min": { [sequelize_1.Op.lte]: amount },
                    "amountConfig.max": { [sequelize_1.Op.gte]: amount },
                }),
                ...(body.location &&
                    body.location !== "any" && {
                    "locationSettings.country": body.location,
                }),
            },
            include: [
                {
                    model: db_1.models.p2pPaymentMethod,
                    as: "paymentMethods",
                    attributes: ["id", "name"],
                    through: { attributes: [] }, // exclude join table fields
                },
                {
                    model: db_1.models.user,
                    as: "user",
                    attributes: [
                        "id",
                        "firstName",
                        "lastName",
                        "avatar",
                        "profile",
                        "emailVerified",
                    ],
                    include: [
                        {
                            model: db_1.models.p2pTrade,
                            as: "p2pTrades",
                            attributes: ["id", "status"],
                        },
                        {
                            model: db_1.models.p2pReview,
                            as: "p2pReviews", // Fixed: use correct alias from user model association
                            attributes: ["communicationRating", "speedRating", "trustRating"],
                            where: {
                                revieweeId: { [sequelize_1.Op.col]: "user.id" } // Only get reviews where user is the reviewee
                            },
                            required: false, // LEFT JOIN to include users with no reviews
                        },
                    ],
                },
            ],
            limit: 30,
            order: [["priceConfig.finalPrice", "ASC"]],
        });
        if (!offers.length) {
            return {
                matches: [],
                matchCount: 0,
                estimatedSavings: 0,
                bestPrice: 0,
            };
        }
        // Extract prices for savings calculation with robust parser
        const prices = offers.map((o) => {
            const priceConfig = (0, json_parser_1.parsePriceConfig)(o.priceConfig);
            return priceConfig.finalPrice;
        });
        const bestPrice = body.tradeType === "buy" ? Math.min(...prices) : Math.max(...prices);
        // Fetch market price via utility (FIAT, SPOT, ECO)
        let marketPrice = null;
        try {
            marketPrice = await getMarketPrice(body.cryptocurrency, offers[0].walletType);
        }
        catch (e) {
            // fallback: use average price
            marketPrice = prices.reduce((a, b) => a + b, 0) / (prices.length || 1);
        }
        // Prepare user criteria payment method ids (as string, since IDs may be UUIDs)
        const userMethodIds = new Set(body.paymentMethods);
        ctx === null || ctx === void 0 ? void 0 : ctx.step(`Scoring and ranking ${offers.length} matching offers`);
        // Transform and score offers
        const scoredOffers = offers.map((offer) => {
            var _a;
            // Parse JSON configs with robust parser
            const priceConfig = (0, json_parser_1.parsePriceConfig)(offer.priceConfig);
            const amountConfig = (0, json_parser_1.parseAmountConfig)(offer.amountConfig);
            // Payment methods
            const paymentMethods = (offer.paymentMethods || []).map((pm) => pm.name);
            // Method overlap: count intersection with userMethodIds
            const offerMethodIds = (offer.paymentMethods || []).map((pm) => pm.id);
            const methodOverlap = offerMethodIds.some((id) => userMethodIds.has(id))
                ? 1
                : 0;
            // Trader info
            const trader = offer.user;
            let traderName = (trader === null || trader === void 0 ? void 0 : trader.firstName) || "Trader";
            if (trader === null || trader === void 0 ? void 0 : trader.lastName)
                traderName += " " + trader.lastName;
            // Trader completion stats
            const trades = (trader === null || trader === void 0 ? void 0 : trader.p2pTrades) || [];
            const completed = trades.filter((t) => t.status === "COMPLETED").length;
            const total = trades.length || 1;
            const completionRate = Math.round((completed / total) * 100);
            // Calculate average rating from p2pReviews (filtered to received reviews)
            const reviews = (trader === null || trader === void 0 ? void 0 : trader.p2pReviews) || [];
            let avgRating = 0;
            if (reviews.length > 0) {
                avgRating =
                    reviews.reduce((sum, r) => sum +
                        (r.communicationRating || 0) +
                        (r.speedRating || 0) +
                        (r.trustRating || 0), 0) /
                        (reviews.length * 3);
                avgRating = Math.round(avgRating * 10) / 10;
            }
            // Verified
            const verified = !!(trader === null || trader === void 0 ? void 0 : trader.emailVerified);
            // Final offer response
            return {
                id: offer.id,
                type: offer.type.toLowerCase(),
                coin: offer.currency,
                walletType: offer.walletType,
                price: priceConfig.finalPrice,
                minLimit: amountConfig.min,
                maxLimit: amountConfig.max,
                availableAmount: amountConfig.availableBalance || amountConfig.total,
                paymentMethods,
                matchScore: calculateMatchScore({
                    price: priceConfig.finalPrice,
                    bestPrice,
                    completionRate,
                    verified,
                    methodOverlap,
                }),
                trader: {
                    id: trader === null || trader === void 0 ? void 0 : trader.id,
                    name: traderName,
                    avatar: trader === null || trader === void 0 ? void 0 : trader.avatar,
                    completedTrades: completed,
                    completionRate,
                    verified,
                    responseTime: 5, // placeholder
                    avgRating,
                },
                benefits: [
                    completionRate > 90 ? "High completion rate" : "Solid completion",
                    avgRating > 90 ? "Highly rated" : "Community trusted",
                    methodOverlap ? "Your preferred payment method" : "Flexible payments",
                    verified ? "KYC Verified" : "Active user",
                ],
                location: ((_a = offer.locationSettings) === null || _a === void 0 ? void 0 : _a.country) || "Global",
                createdAt: offer.createdAt,
                updatedAt: offer.updatedAt,
            };
        });
        // Sort by matchScore DESC
        scoredOffers.sort((a, b) => b.matchScore - a.matchScore);
        // Calculate estimated savings
        let estimatedSavings = 0;
        if (marketPrice && bestPrice) {
            if (body.tradeType === "buy") {
                estimatedSavings = (marketPrice - bestPrice) * amount;
            }
            else if (body.tradeType === "sell") {
                estimatedSavings = (bestPrice - marketPrice) * amount;
            }
            estimatedSavings =
                Math.round((estimatedSavings + Number.EPSILON) * 100) / 100;
        }
        ctx === null || ctx === void 0 ? void 0 : ctx.success(`Found ${scoredOffers.length} matching offers (savings: ${estimatedSavings})`);
        return {
            matches: scoredOffers,
            matchCount: scoredOffers.length,
            estimatedSavings,
            bestPrice,
        };
    }
    catch (err) {
        throw (0, error_1.createError)({
            statusCode: 500,
            message: "Internal Server Error: " + err.message,
        });
    }
};
