"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;
};
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); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DashboardService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("@nestjs/typeorm");
const typeorm_2 = require("typeorm");
const expense_entity_1 = require("../../database/entities/expense.entity");
const expense_split_entity_1 = require("../../database/entities/expense-split.entity");
const settlement_entity_1 = require("../../database/entities/settlement.entity");
const group_member_entity_1 = require("../../database/entities/group-member.entity");
let DashboardService = class DashboardService {
    constructor(expenseRepo, settlementRepo, groupMemberRepo, expenseSplitRepo) {
        this.expenseRepo = expenseRepo;
        this.settlementRepo = settlementRepo;
        this.groupMemberRepo = groupMemberRepo;
        this.expenseSplitRepo = expenseSplitRepo;
    }
    async getDashboard(userId) {
        const [groupSummaries, recentActivity] = await Promise.all([
            this.computeGroupSummaries(userId),
            this.getRecentActivity(userId, 8),
        ]);
        const totalYouOwe = groupSummaries.reduce((sum, g) => sum + g.owes, 0);
        const totalOwedToYou = groupSummaries.reduce((sum, g) => sum + g.owed, 0);
        return {
            totalYouOwe: this.round(totalYouOwe),
            totalOwedToYou: this.round(totalOwedToYou),
            netBalance: this.round(totalOwedToYou - totalYouOwe),
            groupSummaries,
            recentActivity,
        };
    }
    async getRecentActivity(userId, limit = 20) {
        const [expenses, settlements] = await Promise.all([
            this.expenseRepo
                .createQueryBuilder('expense')
                .innerJoin('expense.splits', 'split', 'split.userId = :userId', { userId })
                .leftJoinAndSelect('expense.paidBy', 'paidBy')
                .leftJoinAndSelect('expense.group', 'group')
                .where('expense.isDeleted = false')
                .orderBy('expense.createdAt', 'DESC')
                .take(limit)
                .getMany(),
            this.settlementRepo.find({
                where: [{ payerId: userId }, { payeeId: userId }],
                relations: { payer: true, payee: true },
                order: { createdAt: 'DESC' },
                take: limit,
            }),
        ]);
        const expenseDtos = expenses.map((e) => ({
            id: e.id,
            type: 'expense',
            description: e.description,
            amount: Number(e.amount),
            currency: e.currency,
            category: e.category,
            paidByName: e.paidBy.name,
            groupName: e.group?.name ?? null,
            date: e.date,
            createdAt: e.createdAt,
        }));
        const settlementDtos = settlements.map((s) => ({
            id: s.id,
            type: 'settlement',
            payerName: s.payer.name,
            payeeName: s.payee.name,
            amount: Number(s.amount),
            currency: s.currency,
            isConfirmed: s.isConfirmed,
            createdAt: s.createdAt,
        }));
        return [...expenseDtos, ...settlementDtos]
            .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())
            .slice(0, limit);
    }
    async computeGroupSummaries(userId) {
        const memberships = await this.groupMemberRepo.find({
            where: { userId, leftAt: (0, typeorm_2.IsNull)(), group: { isActive: true } },
            relations: { group: true },
        });
        const summaries = await Promise.all(memberships.map(async ({ group }) => {
            if (!group) {
                return null;
            }
            const [rawOwes, rawOwed, settled, received] = await Promise.all([
                this.sumSplitAmount(userId, group.id, 'owes'),
                this.sumSplitAmount(userId, group.id, 'owed'),
                this.sumSettlements(group.id, userId, 'payerId'),
                this.sumSettlements(group.id, userId, 'payeeId'),
            ]);
            const owes = this.round(Math.max(0, rawOwes - settled));
            const owed = this.round(Math.max(0, rawOwed - received));
            return {
                groupId: group.id,
                groupName: group.name,
                groupImageUrl: group.imageUrl,
                currency: group.currency,
                owes,
                owed,
                net: this.round(owed - owes),
            };
        }));
        return summaries.filter((s) => s !== null)
            .sort((a, b) => Math.abs(b.net) - Math.abs(a.net));
    }
    async sumSplitAmount(userId, groupId, mode) {
        const qb = this.expenseSplitRepo
            .createQueryBuilder('split')
            .innerJoin('split.expense', 'expense')
            .select('COALESCE(SUM(split.amount), 0)', 'total')
            .where('expense.groupId = :groupId', { groupId })
            .andWhere('expense.isDeleted = false');
        if (mode === 'owes') {
            qb.andWhere('split.userId = :userId', { userId })
                .andWhere('expense.paidById != :userId', { userId });
        }
        else {
            qb.andWhere('split.userId != :userId', { userId })
                .andWhere('expense.paidById = :userId', { userId });
        }
        const result = await qb.getRawOne();
        return Number(result?.total ?? 0);
    }
    async sumSettlements(groupId, userId, field) {
        const qb = this.settlementRepo
            .createQueryBuilder('s')
            .select('COALESCE(SUM(s.amount), 0)', 'total')
            .where('s.groupId = :groupId', { groupId })
            .andWhere('s.isConfirmed = true');
        if (field === 'payerId') {
            qb.andWhere('s.payerId = :userId', { userId });
        }
        else {
            qb.andWhere('s.payeeId = :userId', { userId });
        }
        const result = await qb.getRawOne();
        return Number(result?.total ?? 0);
    }
    round(value) {
        return Math.round(value * 100) / 100;
    }
};
exports.DashboardService = DashboardService;
exports.DashboardService = DashboardService = __decorate([
    (0, common_1.Injectable)(),
    __param(0, (0, typeorm_1.InjectRepository)(expense_entity_1.Expense)),
    __param(1, (0, typeorm_1.InjectRepository)(settlement_entity_1.Settlement)),
    __param(2, (0, typeorm_1.InjectRepository)(group_member_entity_1.GroupMember)),
    __param(3, (0, typeorm_1.InjectRepository)(expense_split_entity_1.ExpenseSplit)),
    __metadata("design:paramtypes", [typeorm_2.Repository,
        typeorm_2.Repository,
        typeorm_2.Repository,
        typeorm_2.Repository])
], DashboardService);
//# sourceMappingURL=dashboard.service.js.map