"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateTradeAmount = validateTradeAmount;
exports.validateTradeStatusTransition = validateTradeStatusTransition;
exports.validateOfferStatusTransition = validateOfferStatusTransition;
exports.sanitizeInput = sanitizeInput;
exports.validateMessage = validateMessage;
exports.validatePaymentMethod = validatePaymentMethod;
exports.validateTradeTerms = validateTradeTerms;
exports.validateDisputeReason = validateDisputeReason;
exports.validateEvidenceFile = validateEvidenceFile;
exports.validateLocationSettings = validateLocationSettings;
exports.validateUserRequirements = validateUserRequirements;
exports.validatePriceConfig = validatePriceConfig;
const validator_1 = __importDefault(require("validator"));
const error_1 = require("@b/utils/error");
// Trade status transitions state machine
// Valid DB statuses: PENDING, PAYMENT_SENT, COMPLETED, CANCELLED, DISPUTED, EXPIRED
const TRADE_STATUS_TRANSITIONS = {
    PENDING: ["PAYMENT_SENT", "CANCELLED", "EXPIRED"],
    PAYMENT_SENT: ["COMPLETED", "DISPUTED", "CANCELLED"],
    COMPLETED: ["DISPUTED"], // Can still dispute after completion within time limit
    DISPUTED: ["COMPLETED", "CANCELLED"],
    CANCELLED: [], // Terminal state
    EXPIRED: [], // Terminal state
};
// Offer status transitions
const OFFER_STATUS_TRANSITIONS = {
    DRAFT: ["PENDING_APPROVAL", "CANCELLED"],
    PENDING_APPROVAL: ["ACTIVE", "REJECTED"],
    ACTIVE: ["PAUSED", "COMPLETED", "CANCELLED"],
    PAUSED: ["ACTIVE", "CANCELLED"],
    COMPLETED: [], // Terminal state
    CANCELLED: [], // Terminal state
    REJECTED: [], // Terminal state
    EXPIRED: [], // Terminal state
};
/**
 * Validates trade amount
 */
function validateTradeAmount(amount) {
    if (typeof amount !== "number" || isNaN(amount)) {
        return false;
    }
    // Minimum trade amount (configurable)
    const MIN_TRADE_AMOUNT = 0.0001;
    // Maximum trade amount (configurable)
    const MAX_TRADE_AMOUNT = 1000000;
    return amount >= MIN_TRADE_AMOUNT && amount <= MAX_TRADE_AMOUNT;
}
/**
 * Validates trade status transition
 */
function validateTradeStatusTransition(currentStatus, newStatus) {
    const allowedTransitions = TRADE_STATUS_TRANSITIONS[currentStatus];
    if (!allowedTransitions) {
        return false;
    }
    return allowedTransitions.includes(newStatus);
}
/**
 * Validates offer status transition
 */
function validateOfferStatusTransition(currentStatus, newStatus) {
    const allowedTransitions = OFFER_STATUS_TRANSITIONS[currentStatus];
    if (!allowedTransitions) {
        return false;
    }
    return allowedTransitions.includes(newStatus);
}
/**
 * Sanitizes user input to prevent XSS
 */
function sanitizeInput(input) {
    if (!input || typeof input !== "string") {
        return "";
    }
    // Remove any HTML tags and escape special characters
    return validator_1.default.escape(validator_1.default.stripLow(input.trim()));
}
/**
 * Validates and sanitizes message content
 */
function validateMessage(message) {
    if (!message || typeof message !== "string") {
        throw (0, error_1.createError)({
            statusCode: 400,
            message: "Message must be a non-empty string"
        });
    }
    const sanitized = sanitizeInput(message);
    // Check message length (configurable)
    const MAX_MESSAGE_LENGTH = 1000;
    if (sanitized.length === 0) {
        throw (0, error_1.createError)({
            statusCode: 400,
            message: "Message cannot be empty"
        });
    }
    if (sanitized.length > MAX_MESSAGE_LENGTH) {
        throw (0, error_1.createError)({
            statusCode: 400,
            message: `Message cannot exceed ${MAX_MESSAGE_LENGTH} characters`
        });
    }
    return sanitized;
}
/**
 * Validates payment method data
 */
function validatePaymentMethod(data) {
    if (!data || typeof data !== "object") {
        throw (0, error_1.createError)({
            statusCode: 400,
            message: "Invalid payment method data"
        });
    }
    // Validate name
    if (!data.name || typeof data.name !== "string") {
        throw (0, error_1.createError)({
            statusCode: 400,
            message: "Payment method name is required"
        });
    }
    const name = sanitizeInput(data.name);
    if (name.length < 2 || name.length > 50) {
        throw (0, error_1.createError)({
            statusCode: 400,
            message: "Payment method name must be between 2-50 characters"
        });
    }
    // Validate icon (allow only predefined icons)
    const allowedIcons = [
        "credit-card", "bank", "wallet", "cash", "bitcoin",
        "ethereum", "paypal", "venmo", "zelle", "wire-transfer"
    ];
    const icon = data.icon && allowedIcons.includes(data.icon)
        ? data.icon
        : "credit-card";
    // Validate optional fields
    const result = { name, icon };
    if (data.description) {
        result.description = sanitizeInput(data.description).substring(0, 200);
    }
    if (data.instructions) {
        result.instructions = sanitizeInput(data.instructions).substring(0, 500);
    }
    if (data.processingTime) {
        result.processingTime = sanitizeInput(data.processingTime).substring(0, 50);
    }
    return result;
}
/**
 * Validates trade terms
 */
function validateTradeTerms(terms) {
    if (!terms || typeof terms !== "string") {
        throw (0, error_1.createError)({
            statusCode: 400,
            message: "Trade terms are required"
        });
    }
    const sanitized = sanitizeInput(terms);
    if (sanitized.length < 10) {
        throw (0, error_1.createError)({
            statusCode: 400,
            message: "Trade terms must be at least 10 characters"
        });
    }
    if (sanitized.length > 1000) {
        throw (0, error_1.createError)({
            statusCode: 400,
            message: "Trade terms cannot exceed 1000 characters"
        });
    }
    return sanitized;
}
/**
 * Validates dispute reason
 */
function validateDisputeReason(reason) {
    const validReasons = [
        "PAYMENT_NOT_RECEIVED",
        "PAYMENT_INCORRECT_AMOUNT",
        "CRYPTO_NOT_RELEASED",
        "SELLER_UNRESPONSIVE",
        "BUYER_UNRESPONSIVE",
        "FRAUDULENT_ACTIVITY",
        "TERMS_VIOLATION",
        "OTHER"
    ];
    if (!reason || !validReasons.includes(reason)) {
        throw (0, error_1.createError)({
            statusCode: 400,
            message: "Invalid dispute reason"
        });
    }
    return reason;
}
/**
 * Validates file upload for dispute evidence
 */
function validateEvidenceFile(file) {
    if (!file) {
        return { isValid: false, error: "No file provided" };
    }
    // Check file size (5MB limit)
    const MAX_FILE_SIZE = 5 * 1024 * 1024;
    if (file.size > MAX_FILE_SIZE) {
        return { isValid: false, error: "File size exceeds 5MB limit" };
    }
    // Check file type
    const allowedTypes = [
        "image/jpeg",
        "image/png",
        "image/gif",
        "application/pdf",
        "text/plain"
    ];
    if (!allowedTypes.includes(file.mimetype)) {
        return {
            isValid: false,
            error: "Invalid file type. Allowed: JPEG, PNG, GIF, PDF, TXT"
        };
    }
    // Check file extension
    const allowedExtensions = [".jpg", ".jpeg", ".png", ".gif", ".pdf", ".txt"];
    const ext = file.name.toLowerCase().substring(file.name.lastIndexOf("."));
    if (!allowedExtensions.includes(ext)) {
        return { isValid: false, error: "Invalid file extension" };
    }
    return { isValid: true };
}
/**
 * Validates location settings
 */
function validateLocationSettings(data) {
    if (!data || typeof data !== "object") {
        throw (0, error_1.createError)({
            statusCode: 400,
            message: "Location settings are required"
        });
    }
    if (!data.country || typeof data.country !== "string") {
        throw (0, error_1.createError)({
            statusCode: 400,
            message: "Country is required"
        });
    }
    // Validate country code (ISO 3166-1 alpha-2)
    const country = data.country.toUpperCase();
    if (!validator_1.default.isISO31661Alpha2(country)) {
        throw (0, error_1.createError)({
            statusCode: 400,
            message: "Invalid country code"
        });
    }
    const result = { country };
    if (data.region) {
        result.region = sanitizeInput(data.region).substring(0, 100);
    }
    if (data.city) {
        result.city = sanitizeInput(data.city).substring(0, 100);
    }
    if (data.restrictions && Array.isArray(data.restrictions)) {
        result.restrictions = data.restrictions
            .filter((r) => typeof r === "string" && validator_1.default.isISO31661Alpha2(r))
            .slice(0, 50); // Max 50 restricted countries
    }
    return result;
}
/**
 * Validates user requirements for offers
 */
function validateUserRequirements(data) {
    if (!data || typeof data !== "object") {
        return null;
    }
    const result = {};
    if (typeof data.minCompletedTrades === "number") {
        result.minCompletedTrades = Math.max(0, Math.min(1000, Math.floor(data.minCompletedTrades)));
    }
    if (typeof data.minSuccessRate === "number") {
        result.minSuccessRate = Math.max(0, Math.min(100, data.minSuccessRate));
    }
    if (typeof data.minAccountAge === "number") {
        result.minAccountAge = Math.max(0, Math.min(365, Math.floor(data.minAccountAge)));
    }
    if (typeof data.trustedOnly === "boolean") {
        result.trustedOnly = data.trustedOnly;
    }
    return Object.keys(result).length > 0 ? result : null;
}
/**
 * Validates price configuration
 */
function validatePriceConfig(data, marketPrice) {
    if (!data || typeof data !== "object") {
        throw (0, error_1.createError)({
            statusCode: 400,
            message: "Price configuration is required"
        });
    }
    if (!["FIXED", "MARGIN"].includes(data.model)) {
        throw (0, error_1.createError)({
            statusCode: 400,
            message: "Price model must be FIXED or MARGIN"
        });
    }
    if (typeof data.value !== "number" || data.value <= 0) {
        throw (0, error_1.createError)({
            statusCode: 400,
            message: "Price value must be a positive number"
        });
    }
    let finalPrice;
    if (data.model === "FIXED") {
        finalPrice = data.value;
    }
    else {
        // MARGIN model
        if (!marketPrice || marketPrice <= 0) {
            throw (0, error_1.createError)({
                statusCode: 400,
                message: "Market price is required for margin pricing"
            });
        }
        // Validate margin percentage (-10% to +10%)
        if (data.value < -10 || data.value > 10) {
            throw (0, error_1.createError)({
                statusCode: 400,
                message: "Margin must be between -10% and +10%"
            });
        }
        finalPrice = marketPrice * (1 + data.value / 100);
    }
    return {
        model: data.model,
        value: data.value,
        marketPrice: data.model === "MARGIN" ? marketPrice : undefined,
        finalPrice: parseFloat(finalPrice.toFixed(8)), // 8 decimal places for crypto
    };
}
