"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); }
};
var PackagesService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PackagesService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("@nestjs/typeorm");
const typeorm_2 = require("typeorm");
const package_entity_1 = require("../database/entities/package.entity");
const package_router_assignment_entity_1 = require("../database/entities/package-router-assignment.entity");
const router_entity_1 = require("../database/entities/router.entity");
const business_entity_1 = require("../database/entities/business.entity");
let PackagesService = PackagesService_1 = class PackagesService {
    constructor(packageRepo, assignmentRepo, routerRepo, businessRepo, dataSource) {
        this.packageRepo = packageRepo;
        this.assignmentRepo = assignmentRepo;
        this.routerRepo = routerRepo;
        this.businessRepo = businessRepo;
        this.dataSource = dataSource;
        this.logger = new common_1.Logger(PackagesService_1.name);
    }
    async create(dto, businessId) {
        const business = await this.businessRepo.findOne({ where: { id: businessId } });
        if (!business) {
            throw new common_1.NotFoundException('Business not found');
        }
        const { routerIds, ...packageData } = dto;
        return this.dataSource.transaction(async (manager) => {
            const txPackageRepo = manager.getRepository(package_entity_1.Package);
            const txAssignmentRepo = manager.getRepository(package_router_assignment_entity_1.PackageRouterAssignment);
            const pkg = txPackageRepo.create({
                ...packageData,
                businessId,
                maxDevices: dto.maxDevices ?? 1,
                simultaneousConnections: dto.simultaneousConnections ?? 1,
                gracePeriodMinutes: dto.gracePeriodMinutes ?? 5,
                autoRenew: dto.autoRenew ?? false,
                taxRate: dto.taxRate ?? 16,
                taxInclusive: dto.taxInclusive ?? true,
                sortOrder: dto.sortOrder ?? 0,
                isActive: dto.isActive ?? true,
                isFeatured: dto.isFeatured ?? false,
            });
            const savedPackage = await txPackageRepo.save(pkg);
            if (routerIds && routerIds.length > 0) {
                const assignments = routerIds.map((routerId) => txAssignmentRepo.create({
                    packageId: savedPackage.id,
                    routerId,
                }));
                await txAssignmentRepo.save(assignments);
            }
            this.logger.log(`Package created: ${savedPackage.id} for business ${businessId}`);
            return savedPackage;
        });
    }
    async update(id, dto, businessId) {
        const pkg = await this.findOne(id, businessId);
        const { routerIds, ...updateData } = dto;
        return this.dataSource.transaction(async (manager) => {
            const txPackageRepo = manager.getRepository(package_entity_1.Package);
            const txAssignmentRepo = manager.getRepository(package_router_assignment_entity_1.PackageRouterAssignment);
            Object.assign(pkg, updateData);
            const updatedPackage = await txPackageRepo.save(pkg);
            if (routerIds !== undefined) {
                await txAssignmentRepo.delete({ packageId: id });
                if (routerIds.length > 0) {
                    const assignments = routerIds.map((routerId) => txAssignmentRepo.create({ packageId: id, routerId }));
                    await txAssignmentRepo.save(assignments);
                }
            }
            this.logger.log(`Package updated: ${id} for business ${businessId}`);
            return updatedPackage;
        });
    }
    async delete(id, businessId) {
        const pkg = await this.findOne(id, businessId);
        await this.dataSource.transaction(async (manager) => {
            const txAssignmentRepo = manager.getRepository(package_router_assignment_entity_1.PackageRouterAssignment);
            const txPackageRepo = manager.getRepository(package_entity_1.Package);
            await txAssignmentRepo.delete({ packageId: id });
            pkg.isActive = false;
            await txPackageRepo.save(pkg);
        });
        this.logger.log(`Package soft-deleted: ${id} for business ${businessId}`);
    }
    async duplicate(id, businessId) {
        const original = await this.findOne(id, businessId);
        const { id: _id, createdAt: _createdAt, updatedAt: _updatedAt, business, ...data } = original;
        return this.dataSource.transaction(async (manager) => {
            const txPackageRepo = manager.getRepository(package_entity_1.Package);
            const txAssignmentRepo = manager.getRepository(package_router_assignment_entity_1.PackageRouterAssignment);
            const assignments = await txAssignmentRepo.find({
                where: { packageId: id },
            });
            const duplicate = txPackageRepo.create({
                ...data,
                businessId,
                name: `${data.name || 'Package'} (Copy)`,
                isActive: false,
            });
            const savedDuplicate = await txPackageRepo.save(duplicate);
            if (assignments.length > 0) {
                const newAssignments = assignments.map((a) => txAssignmentRepo.create({
                    packageId: savedDuplicate.id,
                    routerId: a.routerId,
                }));
                await txAssignmentRepo.save(newAssignments);
            }
            this.logger.log(`Package duplicated: ${id} -> ${savedDuplicate.id} for business ${businessId}`);
            return savedDuplicate;
        });
    }
    async findAll(businessId, filters) {
        const where = { businessId };
        if (filters?.isActive !== undefined) {
            where.isActive = filters.isActive;
        }
        if (filters?.isFeatured !== undefined) {
            where.isFeatured = filters.isFeatured;
        }
        if (filters?.type) {
            where.type = filters.type;
        }
        return this.packageRepo.find({
            where,
            order: { sortOrder: 'ASC', createdAt: 'DESC' },
        });
    }
    async findOne(id, businessId) {
        const pkg = await this.packageRepo.findOne({
            where: { id, businessId },
        });
        if (!pkg) {
            throw new common_1.NotFoundException(`Package with ID ${id} not found`);
        }
        return pkg;
    }
    async getPackagesForRouter(routerId) {
        const router = await this.routerRepo.findOne({ where: { id: routerId } });
        if (!router) {
            throw new common_1.NotFoundException('Router not found');
        }
        const assignments = await this.assignmentRepo.find({
            where: { routerId },
            relations: ['package'],
        });
        return assignments
            .map((a) => a.package)
            .filter((p) => p !== null && p !== undefined && p.isActive);
    }
    async assignToRouter(packageId, routerId, businessId) {
        await this.findOne(packageId, businessId);
        const router = await this.routerRepo.findOne({
            where: { id: routerId, businessId },
        });
        if (!router) {
            throw new common_1.NotFoundException('Router not found');
        }
        const existing = await this.assignmentRepo.findOne({
            where: { packageId, routerId },
        });
        if (existing) {
            return existing;
        }
        const assignment = this.assignmentRepo.create({ packageId, routerId });
        const saved = await this.assignmentRepo.save(assignment);
        this.logger.log(`Package ${packageId} assigned to router ${routerId}`);
        return saved;
    }
    async removeFromRouter(packageId, routerId) {
        const assignment = await this.assignmentRepo.findOne({
            where: { packageId, routerId },
        });
        if (!assignment) {
            throw new common_1.NotFoundException('Package-router assignment not found');
        }
        await this.assignmentRepo.remove(assignment);
        this.logger.log(`Package ${packageId} removed from router ${routerId}`);
    }
    async getFeatured(businessId) {
        return this.packageRepo.find({
            where: { businessId, isFeatured: true, isActive: true },
            order: { sortOrder: 'ASC' },
        });
    }
    async toggleActive(id, businessId) {
        const pkg = await this.findOne(id, businessId);
        pkg.isActive = !pkg.isActive;
        const saved = await this.packageRepo.save(pkg);
        this.logger.log(`Package ${id} active toggled: ${saved.isActive}`);
        return saved;
    }
    calculateTax(price, taxRate, taxInclusive) {
        if (taxInclusive) {
            const subtotal = price / (1 + taxRate / 100);
            const taxAmount = price - subtotal;
            return {
                subtotal: Math.round(subtotal * 100) / 100,
                taxAmount: Math.round(taxAmount * 100) / 100,
                total: price,
            };
        }
        const taxAmount = price * (taxRate / 100);
        return {
            subtotal: price,
            taxAmount: Math.round(taxAmount * 100) / 100,
            total: Math.round((price + taxAmount) * 100) / 100,
        };
    }
};
exports.PackagesService = PackagesService;
exports.PackagesService = PackagesService = PackagesService_1 = __decorate([
    (0, common_1.Injectable)(),
    __param(0, (0, typeorm_1.InjectRepository)(package_entity_1.Package)),
    __param(1, (0, typeorm_1.InjectRepository)(package_router_assignment_entity_1.PackageRouterAssignment)),
    __param(2, (0, typeorm_1.InjectRepository)(router_entity_1.Router)),
    __param(3, (0, typeorm_1.InjectRepository)(business_entity_1.Business)),
    __metadata("design:paramtypes", [typeorm_2.Repository,
        typeorm_2.Repository,
        typeorm_2.Repository,
        typeorm_2.Repository,
        typeorm_2.DataSource])
], PackagesService);
