"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PaymentsService = void 0;
const common_1 = require("@nestjs/common");
const mongoose_1 = require("@nestjs/mongoose");
const mongoose_2 = require("mongoose");
const crypto = __importStar(require("crypto"));
const razorpay_1 = __importDefault(require("razorpay"));
const payment_product_schema_1 = require("./schemas/payment-product.schema");
const payment_schema_1 = require("./schemas/payment.schema");
const student_schema_1 = require("../students/schemas/student.schema");
let PaymentsService = class PaymentsService {
    productModel;
    paymentModel;
    studentModel;
    razor;
    constructor(productModel, paymentModel, studentModel) {
        this.productModel = productModel;
        this.paymentModel = paymentModel;
        this.studentModel = studentModel;
        const key_id = process.env.RAZORPAY_KEY_ID;
        const key_secret = process.env.RAZORPAY_KEY_SECRET;
        if (!key_id || !key_secret) {
            throw new Error('Missing Razorpay credentials. Set RAZORPAY_KEY_ID and RAZORPAY_KEY_SECRET.');
        }
        this.razor = new razorpay_1.default({ key_id, key_secret });
    }
    async createProduct(dto) {
        const doc = await this.productModel.create({
            name: dto.name.trim(),
            description: dto.description?.trim(),
            type: dto.type ?? 'other',
            currency: dto.currency ?? 'INR',
            amount: dto.amount,
            academicYearId: dto.academicYearId,
            classId: dto.classId,
            isActive: dto.isActive ?? true,
        });
        return doc.toObject();
    }
    async updateProduct(id, dto) {
        const update = { ...dto };
        if (dto.name)
            update.name = dto.name.trim();
        if (dto.description !== undefined)
            update.description = dto.description?.trim();
        const updated = await this.productModel.findByIdAndUpdate(id, update, { new: true }).lean();
        if (!updated)
            throw new common_1.NotFoundException('Product not found');
        return updated;
    }
    async deleteProduct(id) {
        const res = await this.productModel.findByIdAndDelete(id).lean();
        if (!res)
            throw new common_1.NotFoundException('Product not found');
        return { deleted: true };
    }
    getAllProducts() {
        return this.productModel.find().sort({ createdAt: -1 }).lean();
    }
    getProduct(id) {
        return this.productModel.findById(id).lean();
    }
    async getAvailableProductsForStudent(studentId) {
        const stu = await this.studentModel.findById(studentId, { classId: 1, academicYearId: 1 }).lean();
        if (!stu)
            throw new common_1.UnauthorizedException('Student not found');
        const products = await this.productModel
            .find({ classId: stu.classId, academicYearId: stu.academicYearId, isActive: true })
            .sort({ createdAt: -1 })
            .lean();
        const payments = await this.paymentModel
            .find({ studentId, productId: { $in: products.map(p => String(p._id)) } })
            .lean();
        const statusByProduct = new Map();
        payments.forEach(p => statusByProduct.set(String(p.productId), p));
        return products.map(p => ({
            ...p,
            myPayment: statusByProduct.get(String(p._id)) || null,
        }));
    }
    async createOrder(studentId, body) {
        const product = await this.productModel.findById(body.productId).lean();
        if (!product || !product.isActive)
            throw new common_1.BadRequestException('Invalid product');
        const student = await this.studentModel.findById(studentId, { classId: 1, academicYearId: 1 }).lean();
        if (!student)
            throw new common_1.UnauthorizedException('Student not found');
        if (product.classId !== student.classId || product.academicYearId !== student.academicYearId) {
            throw new common_1.BadRequestException('Product not applicable for your class/academic year');
        }
        const alreadyPaid = await this.paymentModel.findOne({
            studentId,
            productId: body.productId,
            status: 'paid',
        }).lean();
        if (alreadyPaid) {
            throw new common_1.BadRequestException('Payment already completed for this product.');
        }
        const existingOpen = await this.paymentModel.findOne({
            studentId,
            productId: body.productId,
            status: 'created',
        }).lean();
        if (existingOpen?.razorpayOrderId) {
            return {
                orderId: existingOpen.razorpayOrderId,
                amount: product.amount * 100,
                currency: product.currency,
                keyId: process.env.RAZORPAY_KEY_ID,
                paymentId: existingOpen.razorpayPaymentId ?? null,
                localPaymentId: existingOpen._id,
            };
        }
        const order = await this.razor.orders.create({
            amount: product.amount * 100,
            currency: product.currency,
            receipt: `prod_${product._id}_stu_${studentId}_${Date.now()}`,
            notes: {
                productId: String(product._id),
                studentId,
            },
        });
        const payment = await this.paymentModel.create({
            studentId,
            productId: String(product._id),
            academicYearId: product.academicYearId,
            classId: product.classId,
            currency: product.currency,
            amount: product.amount,
            status: 'created',
            razorpayOrderId: order.id,
        });
        return {
            orderId: order.id,
            amount: order.amount,
            currency: order.currency,
            keyId: process.env.RAZORPAY_KEY_ID,
            paymentId: null,
            localPaymentId: payment._id,
        };
    }
    async verifyPayment(studentId, dto) {
        const rec = await this.paymentModel.findOne({
            studentId,
            razorpayOrderId: dto.razorpay_order_id,
        });
        if (!rec)
            throw new common_1.NotFoundException('Payment order not found');
        if (rec.status === 'paid') {
            return { status: 'paid', paymentId: rec.razorpayPaymentId, orderId: rec.razorpayOrderId };
        }
        const secret = process.env.RAZORPAY_KEY_SECRET;
        const sign = crypto
            .createHmac('sha256', secret)
            .update(`${dto.razorpay_order_id}|${dto.razorpay_payment_id}`)
            .digest('hex');
        if (sign !== dto.razorpay_signature) {
            await this.paymentModel.updateOne({ _id: rec._id }, { $set: { status: 'failed', razorpayPaymentId: dto.razorpay_payment_id, razorpaySignature: dto.razorpay_signature } });
            throw new common_1.BadRequestException('Signature verification failed');
        }
        rec.status = 'paid';
        rec.paidAt = new Date();
        rec.razorpayPaymentId = dto.razorpay_payment_id;
        rec.razorpaySignature = dto.razorpay_signature;
        await rec.save();
        return { status: 'paid', paymentId: rec.razorpayPaymentId, orderId: rec.razorpayOrderId };
    }
    async getMyPayments(studentId) {
        return this.paymentModel.find({ studentId }).sort({ createdAt: -1 }).lean();
    }
    async listPayments(filters) {
        const q = {};
        if (filters.academicYearId)
            q.academicYearId = filters.academicYearId;
        if (filters.classId)
            q.classId = filters.classId;
        if (filters.productId)
            q.productId = filters.productId;
        if (filters.studentId)
            q.studentId = filters.studentId;
        if (filters.status)
            q.status = filters.status;
        return this.paymentModel.find(q).sort({ createdAt: -1 }).lean();
    }
    async handleWebhook(signature, rawBody, jsonBody) {
        const webhookSecret = process.env.RAZORPAY_WEBHOOK_SECRET;
        if (!webhookSecret)
            throw new Error('Missing RAZORPAY_WEBHOOK_SECRET');
        const payload = Buffer.isBuffer(rawBody) ? rawBody : Buffer.from(typeof rawBody === 'string' ? rawBody : JSON.stringify(jsonBody));
        const expected = crypto.createHmac('sha256', webhookSecret).update(payload).digest('hex');
        if (expected !== signature)
            throw new common_1.BadRequestException('Invalid webhook signature');
        const event = jsonBody?.event;
        const entity = jsonBody?.payload?.payment?.entity || jsonBody?.payload?.order?.entity;
        if (event === 'payment.captured' && entity) {
            const orderId = entity.order_id;
            const paymentId = entity.id;
            await this.paymentModel.updateOne({ razorpayOrderId: orderId }, { $set: { status: 'paid', paidAt: new Date(), razorpayPaymentId: paymentId } });
        }
        return { received: true };
    }
};
exports.PaymentsService = PaymentsService;
exports.PaymentsService = PaymentsService = __decorate([
    (0, common_1.Injectable)(),
    __param(0, (0, mongoose_1.InjectModel)(payment_product_schema_1.PaymentProduct.name)),
    __param(1, (0, mongoose_1.InjectModel)(payment_schema_1.Payment.name)),
    __param(2, (0, mongoose_1.InjectModel)(student_schema_1.Student.name)),
    __metadata("design:paramtypes", [mongoose_2.Model,
        mongoose_2.Model,
        mongoose_2.Model])
], PaymentsService);
//# sourceMappingURL=payments.service.js.map