"use strict";
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;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SplitCalculatorService = void 0;
const common_1 = require("@nestjs/common");
const enums_1 = require("../../common/enums");
const TOLERANCE = 0.02;
let SplitCalculatorService = class SplitCalculatorService {
    compute(totalAmount, splitType, splits) {
        switch (splitType) {
            case enums_1.SplitType.Equal:
                return this.computeEqual(totalAmount, splits);
            case enums_1.SplitType.Exact:
                return this.computeExact(totalAmount, splits);
            case enums_1.SplitType.Percentage:
                return this.computePercentage(totalAmount, splits);
            case enums_1.SplitType.Shares:
                return this.computeShares(totalAmount, splits);
            default:
                throw new common_1.BadRequestException(`Unknown split type: ${splitType}`);
        }
    }
    computeEqual(total, splits) {
        const n = splits.length;
        const base = this.round(total / n);
        const results = splits.map((s) => ({
            userId: s.userId,
            amount: base,
            percentage: this.round((1 / n) * 100),
            shares: 1,
        }));
        const distributed = this.round(base * n);
        const remainder = this.round(total - distributed);
        results[n - 1].amount = this.round(results[n - 1].amount + remainder);
        return results;
    }
    computeExact(total, splits) {
        splits.forEach((s, i) => {
            if (s.amount === undefined || s.amount === null) {
                throw new common_1.BadRequestException(`splits[${i}].amount is required for EXACT split type`);
            }
        });
        const sum = this.round(splits.reduce((acc, s) => acc + (s.amount ?? 0), 0));
        if (Math.abs(sum - total) > TOLERANCE) {
            throw new common_1.BadRequestException(`Split amounts must sum to the expense total. Got ${sum}, expected ${total}`);
        }
        return splits.map((s) => ({
            userId: s.userId,
            amount: this.round(s.amount),
            percentage: null,
            shares: null,
        }));
    }
    computePercentage(total, splits) {
        splits.forEach((s, i) => {
            if (s.percentage === undefined || s.percentage === null) {
                throw new common_1.BadRequestException(`splits[${i}].percentage is required for PERCENTAGE split type`);
            }
        });
        const sumPct = this.round(splits.reduce((acc, s) => acc + (s.percentage ?? 0), 0));
        if (Math.abs(sumPct - 100) > TOLERANCE) {
            throw new common_1.BadRequestException(`Percentages must sum to 100. Got ${sumPct}`);
        }
        const results = splits.map((s) => ({
            userId: s.userId,
            amount: this.round(total * (s.percentage / 100)),
            percentage: s.percentage,
            shares: null,
        }));
        const distributed = this.round(results.reduce((acc, r) => acc + r.amount, 0));
        const remainder = this.round(total - distributed);
        results[results.length - 1].amount = this.round(results[results.length - 1].amount + remainder);
        return results;
    }
    computeShares(total, splits) {
        splits.forEach((s, i) => {
            if (!s.shares || s.shares < 1) {
                throw new common_1.BadRequestException(`splits[${i}].shares must be a positive integer for SHARES split type`);
            }
        });
        const totalShares = splits.reduce((acc, s) => acc + (s.shares ?? 0), 0);
        const results = splits.map((s) => ({
            userId: s.userId,
            amount: this.round(total * ((s.shares ?? 0) / totalShares)),
            percentage: this.round(((s.shares ?? 0) / totalShares) * 100),
            shares: s.shares,
        }));
        const distributed = this.round(results.reduce((acc, r) => acc + r.amount, 0));
        const remainder = this.round(total - distributed);
        results[results.length - 1].amount = this.round(results[results.length - 1].amount + remainder);
        return results;
    }
    round(value) {
        return Math.round(value * 100) / 100;
    }
};
exports.SplitCalculatorService = SplitCalculatorService;
exports.SplitCalculatorService = SplitCalculatorService = __decorate([
    (0, common_1.Injectable)()
], SplitCalculatorService);
//# sourceMappingURL=split-calculator.service.js.map