"use strict";
/**
 * PresupuestoService - Gestión de Presupuestos de Obra
 *
 * Gestiona presupuestos de obra con sus partidas.
 * Soporta versionamiento y aprobación.
 *
 * @module Budgets
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.PresupuestoService = void 0;
const base_service_1 = require("../../../shared/services/base.service");
class PresupuestoService extends base_service_1.BaseService {
    partidaRepository;
    constructor(repository, partidaRepository) {
        super(repository);
        this.partidaRepository = partidaRepository;
    }
    /**
     * Crear nuevo presupuesto
     */
    async createPresupuesto(ctx, data) {
        return this.create(ctx, {
            ...data,
            version: 1,
            isActive: true,
            totalAmount: 0,
        });
    }
    /**
     * Obtener presupuestos por fraccionamiento
     */
    async findByFraccionamiento(ctx, fraccionamientoId, page = 1, limit = 20) {
        return this.findAll(ctx, {
            page,
            limit,
            where: { fraccionamientoId, isActive: true },
        });
    }
    /**
     * Obtener presupuesto con sus partidas
     */
    async findWithPartidas(ctx, id) {
        return this.repository.findOne({
            where: {
                id,
                tenantId: ctx.tenantId,
                deletedAt: null,
            },
            relations: ['partidas', 'partidas.concepto'],
        });
    }
    /**
     * Agregar partida al presupuesto
     */
    async addPartida(ctx, presupuestoId, data) {
        const presupuesto = await this.findById(ctx, presupuestoId);
        if (!presupuesto) {
            throw new Error('Presupuesto not found');
        }
        const partida = this.partidaRepository.create({
            tenantId: ctx.tenantId,
            presupuestoId,
            conceptoId: data.conceptoId,
            quantity: data.quantity,
            unitPrice: data.unitPrice,
            sequence: data.sequence || 0,
            createdById: ctx.userId,
        });
        const savedPartida = await this.partidaRepository.save(partida);
        await this.recalculateTotal(ctx, presupuestoId);
        return savedPartida;
    }
    /**
     * Actualizar partida
     */
    async updatePartida(ctx, partidaId, data) {
        const partida = await this.partidaRepository.findOne({
            where: {
                id: partidaId,
                tenantId: ctx.tenantId,
                deletedAt: null,
            },
        });
        if (!partida) {
            return null;
        }
        const updated = this.partidaRepository.merge(partida, {
            ...data,
            updatedById: ctx.userId,
        });
        const saved = await this.partidaRepository.save(updated);
        await this.recalculateTotal(ctx, partida.presupuestoId);
        return saved;
    }
    /**
     * Eliminar partida
     */
    async removePartida(ctx, partidaId) {
        const partida = await this.partidaRepository.findOne({
            where: {
                id: partidaId,
                tenantId: ctx.tenantId,
            },
        });
        if (!partida) {
            return false;
        }
        await this.partidaRepository.update({ id: partidaId }, {
            deletedAt: new Date(),
            deletedById: ctx.userId,
        });
        await this.recalculateTotal(ctx, partida.presupuestoId);
        return true;
    }
    /**
     * Recalcular total del presupuesto
     */
    async recalculateTotal(ctx, presupuestoId) {
        const result = await this.partidaRepository
            .createQueryBuilder('p')
            .select('SUM(p.quantity * p.unit_price)', 'total')
            .where('p.presupuesto_id = :presupuestoId', { presupuestoId })
            .andWhere('p.deleted_at IS NULL')
            .getRawOne();
        const total = parseFloat(result?.total || '0');
        await this.repository.update({ id: presupuestoId }, { totalAmount: total, updatedById: ctx.userId });
    }
    /**
     * Crear nueva versión del presupuesto
     */
    async createNewVersion(ctx, presupuestoId) {
        const original = await this.findWithPartidas(ctx, presupuestoId);
        if (!original) {
            throw new Error('Presupuesto not found');
        }
        // Desactivar versión anterior
        await this.repository.update({ id: presupuestoId }, { isActive: false, updatedById: ctx.userId });
        // Crear nueva versión
        const newVersion = await this.create(ctx, {
            code: original.code,
            name: original.name,
            description: original.description,
            fraccionamientoId: original.fraccionamientoId,
            prototipoId: original.prototipoId,
            currencyId: original.currencyId,
            version: original.version + 1,
            isActive: true,
            totalAmount: original.totalAmount,
        });
        // Copiar partidas
        for (const partida of original.partidas) {
            await this.partidaRepository.save(this.partidaRepository.create({
                tenantId: ctx.tenantId,
                presupuestoId: newVersion.id,
                conceptoId: partida.conceptoId,
                quantity: partida.quantity,
                unitPrice: partida.unitPrice,
                sequence: partida.sequence,
                createdById: ctx.userId,
            }));
        }
        return newVersion;
    }
    /**
     * Aprobar presupuesto
     */
    async approve(ctx, presupuestoId) {
        const presupuesto = await this.findById(ctx, presupuestoId);
        if (!presupuesto) {
            return null;
        }
        return this.update(ctx, presupuestoId, {
            approvedAt: new Date(),
            approvedById: ctx.userId,
        });
    }
}
exports.PresupuestoService = PresupuestoService;
//# sourceMappingURL=presupuesto.service.js.map