"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LoanStatementStatusService = void 0;
const mongoose_1 = __importDefault(require("mongoose"));
const dayjs_1 = __importDefault(require("dayjs"));
const LoanStatementStatus_model_1 = require("../models/LoanStatementStatus.model");
const event_map_1 = require("../microservice/event-map");
const queue_map_1 = require("../microservice/queue-map");
class LoanStatementStatusService {
    getLoanChargesService;
    termLoanService;
    mainQueueService;
    constructor(getLoanChargesService, termLoanService, mainQueueService) {
        this.getLoanChargesService = getLoanChargesService;
        this.termLoanService = termLoanService;
        this.mainQueueService = mainQueueService;
    }
    async initStatementStatuses() {
        const allStatuses = await LoanStatementStatus_model_1.LoanStatementStatusModel.find().lean();
        if (allStatuses.length === 0) {
            const loanChargesService = this.getLoanChargesService();
            const loanProducts = await loanChargesService.getAllLoanProducts();
            const endDate = (0, dayjs_1.default)().utcOffset(0).startOf('month');
            for (const product of loanProducts) {
                let currentDate = (0, dayjs_1.default)(product.startDate).utcOffset(0).startOf('month');
                while (currentDate.diff(endDate, 'month') <= 0) {
                    const statementDate = this.getStatementDateForDate(currentDate.toDate());
                    await this.getCreateStatementStatus(product._id.toString(), statementDate);
                    currentDate = currentDate.add(1, 'month');
                }
            }
        }
    }
    getStatementDateFromStringPeriod(period) {
        let startOf = null;
        switch (period) {
            case 'CURRENT_MONTH':
                startOf = (0, dayjs_1.default)().utcOffset(0).startOf('month');
                break;
            case 'LAST_MONTH':
                startOf = (0, dayjs_1.default)().utcOffset(0).startOf('month').subtract(1, 'second').startOf('month');
                break;
        }
        if (!startOf) {
            return startOf;
        }
        return { year: startOf.year(), month: startOf.month() + 1 };
    }
    getStatementDateForDate(date) {
        const startOf = (0, dayjs_1.default)(date).utcOffset(0).startOf('month');
        return { year: startOf.year(), month: startOf.month() + 1 };
    }
    getStatementDateFromPeriod(period) {
        return { year: period.start.year(), month: period.start.month() + 1 };
    }
    getDateFromStatementDate(statementDate) {
        return (0, dayjs_1.default)().utcOffset(0).set('year', statementDate.year).set('month', statementDate.month - 1).startOf('month').toDate();
    }
    getPeriodsFromStatementDate(statementDate) {
        if (statementDate.month < 1 || statementDate.month > 12) {
            throw new Error('Invalid month number. Month should be between 1 and 12.');
        }
        const startOfMonth = (0, dayjs_1.default)()
            .set('year', statementDate.year)
            .set('month', statementDate.month - 1)
            .utcOffset(0)
            .startOf('month');
        const endOfMonth = startOfMonth.endOf('month');
        return [{ start: startOfMonth, end: endOfMonth }];
    }
    async toggleStatementLock(productId, statementDate) {
        const statementStatus = await this.getCreateStatementStatus(productId, statementDate);
        if (statementStatus) {
            statementStatus.locked = !statementStatus.locked;
            await statementStatus.save();
        }
    }
    async updateStatementStatus(productId, statementDate, actual) {
        const statementStatus = await this.getCreateStatementStatus(productId, statementDate);
        if (statementStatus && !statementStatus.locked) {
            statementStatus.actual = actual;
            if (actual) {
                statementStatus.lastCalculated = new Date();
            }
            await statementStatus.save();
        }
    }
    async getAllStatementsStatus(statementDate) {
        await this.initStatementStatuses();
        const loanChargesService = this.getLoanChargesService();
        const products = await loanChargesService.getAllLoanProducts();
        const results = await Promise.all(products.map(async (product) => {
            const statementsStatus = await LoanStatementStatus_model_1.LoanStatementStatusModel.findOne({ productId: product._id, ...statementDate }).lean();
            if (statementsStatus) {
                return { ...statementsStatus, product };
            }
            return null;
        }));
        return results.filter((res) => !!res);
    }
    async getStatementStatus(productId, date) {
        const statementDate = this.getStatementDateForDate(date);
        return this.getCreateStatementStatus(productId, statementDate);
    }
    async getCreateStatementStatus(productId, statementDate) {
        const statementStatus = await LoanStatementStatus_model_1.LoanStatementStatusModel.findOne({ productId, ...statementDate });
        if (statementStatus) {
            return statementStatus;
        }
        else {
            const loanStatementStatus = {
                productId: new mongoose_1.default.Types.ObjectId(productId),
                year: statementDate.year,
                month: statementDate.month,
                actual: true,
                locked: false,
                lastCalculated: null,
            };
            const newStatementStatus = new LoanStatementStatus_model_1.LoanStatementStatusModel(loanStatementStatus);
            await newStatementStatus.save();
            return newStatementStatus;
        }
    }
    async validateDate(productId, date) {
        try {
            const statementsStatus = await this.getStatementStatus(productId, date);
            if (statementsStatus && statementsStatus.locked) {
                return 'Statement is locked!';
            }
            return null;
        }
        catch (error) {
            console.error(error);
            return 'Internal Server Error';
        }
    }
    async getBorrowerStatement(borrowerId) {
        try {
            const lastStatementDate = this.getStatementDateFromStringPeriod('LAST_MONTH');
            const currentStatementDate = this.getStatementDateFromStringPeriod('CURRENT_MONTH');
            const lastStatus = await this.getBorrowerMonthStatus(borrowerId, lastStatementDate);
            const currentStatus = await this.getBorrowerMonthStatus(borrowerId, currentStatementDate);
            const termLoanStatus = await this.termLoanService.isBorrowerTermLoanActual(borrowerId);
            return { 'LAST_MONTH': lastStatus, 'CURRENT_MONTH': currentStatus, 'TERM_LOAN': termLoanStatus };
        }
        catch (e) {
            console.error(e);
            throw e;
        }
    }
    async getBorrowerMonthStatus(borrowerId, statementDate) {
        const loanChargesService = this.getLoanChargesService();
        const products = await loanChargesService.getLoanProducts(borrowerId);
        const lastResults = await Promise.all(products.map(async (product) => {
            return await this.getCreateStatementStatus(product._id.toString(), statementDate);
        }));
        return lastResults.reduce((acc, res) => res.actual && acc, true);
    }
    async recalculateStatementQueued(productMap) {
        this.mainQueueService.sendTaskToQueue({
            data: { productMap },
            pattern: event_map_1.EventMap.recalc.STATEMENT_STATUS,
        }, queue_map_1.QueueMap.main).catch(console.error);
    }
}
exports.LoanStatementStatusService = LoanStatementStatusService;
