"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 AdminService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("@nestjs/typeorm");
const typeorm_2 = require("@nestjs/typeorm");
const typeorm_3 = require("typeorm");
const jwt_1 = require("@nestjs/jwt");
const child_process_1 = require("child_process");
const util_1 = require("util");
const business_entity_1 = require("../database/entities/business.entity");
const user_entity_1 = require("../database/entities/user.entity");
const role_entity_1 = require("../database/entities/role.entity");
const permission_entity_1 = require("../database/entities/permission.entity");
const payment_entity_1 = require("../database/entities/payment.entity");
const subscription_entity_1 = require("../database/entities/subscription.entity");
const subscription_plan_entity_1 = require("../database/entities/subscription-plan.entity");
const router_entity_1 = require("../database/entities/router.entity");
const location_entity_1 = require("../database/entities/location.entity");
const commission_entity_1 = require("../database/entities/commission.entity");
const audit_log_entity_1 = require("../database/entities/audit-log.entity");
const api_log_entity_1 = require("../database/entities/api-log.entity");
const failed_job_entity_1 = require("../database/entities/failed-job.entity");
const system_settings_entity_1 = require("../database/entities/system-settings.entity");
const business_settings_entity_1 = require("../database/entities/business-settings.entity");
const customer_entity_1 = require("../database/entities/customer.entity");
const config_service_1 = require("../common/config/config.service");
const encryption_util_1 = require("../common/utils/encryption.util");
const execAsync = (0, util_1.promisify)(child_process_1.exec);
let AdminService = AdminService_1 = class AdminService {
    constructor(businessRepo, userRepo, roleRepo, permissionRepo, paymentRepo, subscriptionRepo, subscriptionPlanRepo, routerRepo, locationRepo, commissionRepo, auditLogRepo, apiLogRepo, failedJobRepo, systemSettingsRepo, businessSettingsRepo, customerRepo, jwtService, configService, dataSource) {
        this.businessRepo = businessRepo;
        this.userRepo = userRepo;
        this.roleRepo = roleRepo;
        this.permissionRepo = permissionRepo;
        this.paymentRepo = paymentRepo;
        this.subscriptionRepo = subscriptionRepo;
        this.subscriptionPlanRepo = subscriptionPlanRepo;
        this.routerRepo = routerRepo;
        this.locationRepo = locationRepo;
        this.commissionRepo = commissionRepo;
        this.auditLogRepo = auditLogRepo;
        this.apiLogRepo = apiLogRepo;
        this.failedJobRepo = failedJobRepo;
        this.systemSettingsRepo = systemSettingsRepo;
        this.businessSettingsRepo = businessSettingsRepo;
        this.customerRepo = customerRepo;
        this.jwtService = jwtService;
        this.configService = configService;
        this.dataSource = dataSource;
        this.logger = new common_1.Logger(AdminService_1.name);
    }
    async getAllBusinesses(filters) {
        const page = filters?.page || 1;
        const limit = filters?.limit || 20;
        const skip = (page - 1) * limit;
        const queryBuilder = this.businessRepo
            .createQueryBuilder('business')
            .leftJoinAndSelect('business.subscription', 'subscription')
            .leftJoinAndSelect('subscription.plan', 'plan');
        if (filters?.status) {
            if (filters.status === 'active') {
                queryBuilder.andWhere('business.isActive = :isActive', { isActive: true });
                queryBuilder.andWhere('business.isSuspended = :isSuspended', { isSuspended: false });
            }
            else if (filters.status === 'suspended') {
                queryBuilder.andWhere('business.isSuspended = :isSuspended', { isSuspended: true });
            }
            else if (filters.status === 'trial') {
                queryBuilder.andWhere('subscription.status = :status', { status: subscription_entity_1.SubscriptionStatus.TRIAL });
            }
        }
        if (filters?.search) {
            queryBuilder.andWhere('(business.name ILIKE :search OR business.email ILIKE :search OR business.slug ILIKE :search)', { search: `%${filters.search}%` });
        }
        queryBuilder.orderBy('business.createdAt', 'DESC');
        queryBuilder.skip(skip).take(limit);
        const [businesses, total] = await queryBuilder.getManyAndCount();
        const data = await Promise.all(businesses.map(async (biz) => {
            const [routerCount, locationCount, staffCount, customerCount, revenueRow] = await Promise.all([
                this.routerRepo.count({ where: { businessId: biz.id } }),
                this.locationRepo.count({ where: { businessId: biz.id } }),
                this.userRepo.count({ where: { businessId: biz.id, isActive: true } }),
                this.customerRepo.count({ where: { businessId: biz.id } }),
                this.paymentRepo
                    .createQueryBuilder('payment')
                    .select('COALESCE(SUM(payment.amount), 0)', 'sum')
                    .where('payment.businessId = :businessId', { businessId: biz.id })
                    .andWhere('payment.status = :status', { status: payment_entity_1.PaymentStatus.SUCCESSFUL })
                    .getRawOne(),
            ]);
            return {
                ...biz,
                stats: {
                    routerCount,
                    locationCount,
                    staffCount,
                    customerCount,
                    revenueTotal: parseFloat(revenueRow?.sum || '0'),
                },
            };
        }));
        return { data, total, page, limit };
    }
    async getBusinessDetail(businessId) {
        const business = await this.businessRepo.findOne({
            where: { id: businessId },
            relations: ['subscription', 'subscription.plan'],
        });
        if (!business) {
            throw new common_1.NotFoundException(`Business ${businessId} not found`);
        }
        const [routerCount, locationCount, staffCount, customerCount, paymentCount, paymentVolume] = await Promise.all([
            this.routerRepo.count({ where: { businessId } }),
            this.locationRepo.count({ where: { businessId } }),
            this.userRepo.count({ where: { businessId, isActive: true } }),
            this.customerRepo.count({ where: { businessId } }),
            this.paymentRepo.count({ where: { businessId } }),
            this.paymentRepo
                .createQueryBuilder('payment')
                .select('COALESCE(SUM(payment.amount), 0)', 'sum')
                .where('payment.businessId = :businessId', { businessId })
                .andWhere('payment.status = :status', { status: payment_entity_1.PaymentStatus.SUCCESSFUL })
                .getRawOne(),
        ]);
        return {
            ...business,
            routerCount,
            locationCount,
            staffCount,
            customerCount,
            paymentCount,
            paymentVolume: parseFloat(paymentVolume?.sum || '0'),
        };
    }
    async createBusiness(dto) {
        const existingBusiness = await this.businessRepo.findOne({
            where: { name: dto.businessName },
        });
        if (existingBusiness) {
            throw new common_1.BadRequestException('Business name already exists');
        }
        const existingUser = await this.userRepo.findOne({
            where: { email: dto.ownerEmail },
        });
        if (existingUser) {
            throw new common_1.BadRequestException('Owner email already registered');
        }
        const plan = await this.subscriptionPlanRepo.findOne({
            where: { id: dto.subscriptionPlanId },
        });
        if (!plan) {
            throw new common_1.NotFoundException('Subscription plan not found');
        }
        const slug = dto.businessName
            .toLowerCase()
            .replace(/[^a-z0-9]+/g, '-')
            .replace(/^-|-$/g, '');
        const business = this.businessRepo.create({
            name: dto.businessName,
            slug,
            email: dto.ownerEmail,
            isActive: true,
            isSuspended: false,
            maxRouters: plan.maxRouters,
            maxLocations: plan.maxLocations,
            maxStaff: plan.maxStaff,
            maxCustomers: plan.maxCustomers,
        });
        const savedBusiness = await this.businessRepo.save(business);
        let ownerRole = await this.roleRepo.findOne({
            where: { type: role_entity_1.RoleType.BUSINESS_OWNER },
        });
        if (!ownerRole) {
            ownerRole = this.roleRepo.create({
                name: 'business_owner',
                type: role_entity_1.RoleType.BUSINESS_OWNER,
                description: 'Business owner role',
                isSystem: true,
            });
            ownerRole = await this.roleRepo.save(ownerRole);
        }
        const passwordHash = await (0, encryption_util_1.hashPassword)(dto.ownerPassword);
        const owner = this.userRepo.create({
            email: dto.ownerEmail,
            passwordHash,
            firstName: dto.ownerFirstName,
            lastName: dto.ownerLastName,
            roleId: ownerRole.id,
            businessId: savedBusiness.id,
            isActive: true,
        });
        const savedOwner = await this.userRepo.save(owner);
        const trialDays = dto.trialDays ?? 14;
        const now = new Date();
        const trialEnd = new Date(now);
        trialEnd.setDate(trialEnd.getDate() + trialDays);
        const subscription = this.subscriptionRepo.create({
            businessId: savedBusiness.id,
            planId: plan.id,
            status: subscription_entity_1.SubscriptionStatus.TRIAL,
            startDate: now,
            trialEndDate: trialEnd,
            priceKes: plan.priceKes,
            autoRenew: true,
        });
        const savedSubscription = await this.subscriptionRepo.save(subscription);
        savedBusiness.subscriptionId = savedSubscription.id;
        savedBusiness.subscriptionStartDate = now;
        await this.businessRepo.save(savedBusiness);
        await this.auditLogRepo.save(this.auditLogRepo.create({
            businessId: savedBusiness.id,
            action: 'BUSINESS_CREATED',
            entityType: 'Business',
            entityId: savedBusiness.id,
            newValue: { name: dto.businessName, ownerEmail: dto.ownerEmail },
        }));
        this.logger.log(`Business created: ${savedBusiness.id} with owner ${savedOwner.id}`);
        return { business: savedBusiness, owner: savedOwner };
    }
    async suspendBusiness(businessId, reason) {
        const business = await this.businessRepo.findOne({ where: { id: businessId } });
        if (!business) {
            throw new common_1.NotFoundException(`Business ${businessId} not found`);
        }
        if (business.isSuspended) {
            throw new common_1.BadRequestException('Business is already suspended');
        }
        business.isSuspended = true;
        business.isActive = false;
        business.suspendedReason = reason;
        const updated = await this.businessRepo.save(business);
        await this.auditLogRepo.save(this.auditLogRepo.create({
            businessId,
            action: 'BUSINESS_SUSPENDED',
            entityType: 'Business',
            entityId: businessId,
            newValue: { isSuspended: true, reason },
        }));
        this.logger.log(`Business ${businessId} suspended: ${reason}`);
        return updated;
    }
    async unsuspendBusiness(businessId) {
        const business = await this.businessRepo.findOne({ where: { id: businessId } });
        if (!business) {
            throw new common_1.NotFoundException(`Business ${businessId} not found`);
        }
        if (!business.isSuspended) {
            throw new common_1.BadRequestException('Business is not suspended');
        }
        business.isSuspended = false;
        business.isActive = true;
        business.suspendedReason = null;
        const updated = await this.businessRepo.save(business);
        await this.auditLogRepo.save(this.auditLogRepo.create({
            businessId,
            action: 'BUSINESS_UNSUSPENDED',
            entityType: 'Business',
            entityId: businessId,
            newValue: { isSuspended: false },
        }));
        this.logger.log(`Business ${businessId} unsuspended`);
        return updated;
    }
    async deleteBusiness(businessId) {
        const business = await this.businessRepo.findOne({ where: { id: businessId } });
        if (!business) {
            throw new common_1.NotFoundException(`Business ${businessId} not found`);
        }
        business.isActive = false;
        const subscriptions = await this.subscriptionRepo.find({
            where: { businessId, status: subscription_entity_1.SubscriptionStatus.ACTIVE },
        });
        for (const sub of subscriptions) {
            sub.status = subscription_entity_1.SubscriptionStatus.CANCELLED;
            sub.cancelledAt = new Date();
            sub.cancelledReason = 'Business deleted';
            await this.subscriptionRepo.save(sub);
        }
        await this.businessRepo.save(business);
        await this.auditLogRepo.save(this.auditLogRepo.create({
            businessId,
            action: 'BUSINESS_DELETED',
            entityType: 'Business',
            entityId: businessId,
            newValue: { isActive: false },
        }));
        this.logger.log(`Business ${businessId} soft-deleted`);
        return { success: true };
    }
    async impersonateBusiness(businessId, impersonatingAdminId) {
        const business = await this.businessRepo.findOne({
            where: { id: businessId },
        });
        if (!business) {
            throw new common_1.NotFoundException(`Business ${businessId} not found`);
        }
        const admin = await this.userRepo.findOne({
            where: { id: impersonatingAdminId },
            relations: ['role'],
        });
        if (!admin) {
            throw new common_1.NotFoundException('Admin user not found');
        }
        const payload = {
            sub: admin.id,
            email: admin.email,
            role: admin.role?.type ?? admin.role?.name,
            businessId: business.id,
            impersonating: true,
            originalBusinessId: admin.businessId,
        };
        const token = this.jwtService.sign(payload, {
            expiresIn: '1h',
        });
        await this.auditLogRepo.save(this.auditLogRepo.create({
            businessId: business.id,
            userId: impersonatingAdminId,
            action: 'ADMIN_IMPERSONATION',
            entityType: 'Business',
            entityId: business.id,
            newValue: { adminId: impersonatingAdminId },
        }));
        this.logger.log(`Admin ${impersonatingAdminId} impersonating business ${businessId}`);
        return { token, business };
    }
    async getPlatformOverview() {
        const [totalBusinesses, activeBusinesses, suspendedBusinesses, trialBusinesses, totalCustomers, paymentStats, commissionTotal, activeSubscriptions, trialSubscriptions, cancelledSubscriptions, expiredSubscriptions, totalRouters,] = await Promise.all([
            this.businessRepo.count(),
            this.businessRepo.count({ where: { isActive: true, isSuspended: false } }),
            this.businessRepo.count({ where: { isSuspended: true } }),
            this.subscriptionRepo.count({ where: { status: subscription_entity_1.SubscriptionStatus.TRIAL } }),
            this.customerRepo.count(),
            this.paymentRepo
                .createQueryBuilder('payment')
                .select([
                'COALESCE(SUM(payment.amount), 0) as volume',
                'COUNT(payment.id) as count',
            ])
                .where('payment.status = :status', { status: payment_entity_1.PaymentStatus.SUCCESSFUL })
                .getRawOne(),
            this.commissionRepo
                .createQueryBuilder('commission')
                .select('COALESCE(SUM(commission.amount), 0)', 'sum')
                .getRawOne(),
            this.subscriptionRepo.count({ where: { status: subscription_entity_1.SubscriptionStatus.ACTIVE } }),
            this.subscriptionRepo.count({ where: { status: subscription_entity_1.SubscriptionStatus.TRIAL } }),
            this.subscriptionRepo.count({ where: { status: subscription_entity_1.SubscriptionStatus.CANCELLED } }),
            this.subscriptionRepo.count({ where: { status: subscription_entity_1.SubscriptionStatus.EXPIRED } }),
            this.routerRepo.count(),
        ]);
        const revenueTrend = await this.getMonthlyRevenueTrend();
        return {
            businesses: {
                total: totalBusinesses,
                active: activeBusinesses,
                suspended: suspendedBusinesses,
                trial: trialBusinesses,
            },
            customers: {
                total: totalCustomers,
            },
            payments: {
                volume: parseFloat(paymentStats?.volume || '0'),
                count: parseInt(paymentStats?.count || '0', 10),
            },
            commission: {
                total: parseFloat(commissionTotal?.sum || '0'),
            },
            subscriptions: {
                active: activeSubscriptions,
                trial: trialSubscriptions,
                cancelled: cancelledSubscriptions,
                expired: expiredSubscriptions,
            },
            revenueTrend,
            routers: {
                total: totalRouters,
            },
        };
    }
    async getPlatformRevenue(startDate, endDate) {
        const start = startDate ? new Date(startDate) : new Date(new Date().setMonth(new Date().getMonth() - 12));
        const end = endDate ? new Date(endDate) : new Date();
        const [commRows, payRows] = await Promise.all([
            this.commissionRepo
                .createQueryBuilder('commission')
                .select(['commission.createdAt as createdAt', 'commission.amount as amount'])
                .where('commission.createdAt >= :start', { start })
                .andWhere('commission.createdAt <= :end', { end })
                .getRawMany(),
            this.paymentRepo
                .createQueryBuilder('payment')
                .select(['payment.createdAt as createdAt', 'payment.amount as amount'])
                .where('payment.status = :status', { status: payment_entity_1.PaymentStatus.SUCCESSFUL })
                .andWhere('payment.createdAt >= :start', { start })
                .andWhere('payment.createdAt <= :end', { end })
                .getRawMany(),
        ]);
        const makeKey = (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`;
        const revMap = new Map();
        for (const r of payRows) {
            const dt = r.createdAt instanceof Date ? r.createdAt : new Date(r.createdAt);
            if (isNaN(dt.getTime()))
                continue;
            const k = makeKey(dt);
            revMap.set(k, (revMap.get(k) || 0) + Number(r.amount || 0));
        }
        const commMap = new Map();
        for (const r of commRows) {
            const dt = r.createdAt instanceof Date ? r.createdAt : new Date(r.createdAt);
            if (isNaN(dt.getTime()))
                continue;
            const k = makeKey(dt);
            commMap.set(k, (commMap.get(k) || 0) + Number(r.amount || 0));
        }
        const breakdown = [];
        let total = 0;
        const cur = new Date(end.getFullYear(), end.getMonth(), 1);
        const min = new Date(start.getFullYear(), start.getMonth(), 1);
        while (cur >= min) {
            const k = makeKey(cur);
            const revenue = revMap.get(k) || 0;
            const commission = commMap.get(k) || 0;
            breakdown.unshift({ month: k, revenue, commission });
            total += commission;
            cur.setMonth(cur.getMonth() - 1);
        }
        return { total: Math.round(total * 100) / 100, breakdown };
    }
    async getCommissions(filters) {
        const page = filters?.page || 1;
        const limit = filters?.limit || 20;
        const skip = (page - 1) * limit;
        const queryBuilder = this.commissionRepo
            .createQueryBuilder('commission')
            .leftJoinAndSelect('commission.business', 'business')
            .leftJoinAndSelect('commission.payment', 'payment');
        if (filters?.businessId) {
            queryBuilder.andWhere('commission.businessId = :businessId', { businessId: filters.businessId });
        }
        if (filters?.status) {
            queryBuilder.andWhere('commission.status = :status', { status: filters.status });
        }
        if (filters?.startDate) {
            queryBuilder.andWhere('commission.createdAt >= :startDate', { startDate: new Date(filters.startDate) });
        }
        if (filters?.endDate) {
            queryBuilder.andWhere('commission.createdAt <= :endDate', { endDate: new Date(filters.endDate) });
        }
        queryBuilder.orderBy('commission.createdAt', 'DESC');
        queryBuilder.skip(skip).take(limit);
        const [data, total] = await queryBuilder.getManyAndCount();
        return { data, total, page, limit };
    }
    async updateCommission(commissionId, dto) {
        const commission = await this.commissionRepo.findOne({
            where: { id: commissionId },
        });
        if (!commission) {
            throw new common_1.NotFoundException(`Commission ${commissionId} not found`);
        }
        commission.status = dto.status === 'PAID' ? commission_entity_1.CommissionStatus.PAID : commission_entity_1.CommissionStatus.PENDING;
        if (dto.status === 'PAID') {
            commission.paidAt = new Date();
        }
        const updated = await this.commissionRepo.save(commission);
        await this.auditLogRepo.save(this.auditLogRepo.create({
            businessId: commission.businessId,
            action: 'COMMISSION_UPDATED',
            entityType: 'Commission',
            entityId: commissionId,
            newValue: { status: dto.status },
        }));
        this.logger.log(`Commission ${commissionId} updated to ${dto.status}`);
        return updated;
    }
    async getSystemLogs(filters) {
        const page = filters?.page || 1;
        const limit = filters?.limit || 50;
        const skip = (page - 1) * limit;
        const queryBuilder = this.apiLogRepo.createQueryBuilder('log');
        if (filters?.startDate) {
            queryBuilder.andWhere('log.createdAt >= :startDate', { startDate: new Date(filters.startDate) });
        }
        if (filters?.endDate) {
            queryBuilder.andWhere('log.createdAt <= :endDate', { endDate: new Date(filters.endDate) });
        }
        if (filters?.method) {
            queryBuilder.andWhere('log.method = :method', { method: filters.method.toUpperCase() });
        }
        if (filters?.statusCode) {
            queryBuilder.andWhere('log.statusCode = :statusCode', { statusCode: filters.statusCode });
        }
        if (filters?.search) {
            queryBuilder.andWhere('(log.url ILIKE :search OR log.ipAddress ILIKE :search)', { search: `%${filters.search}%` });
        }
        queryBuilder.orderBy('log.createdAt', 'DESC');
        queryBuilder.skip(skip).take(limit);
        const [data, total] = await queryBuilder.getManyAndCount();
        return { data, total, page, limit };
    }
    async getAuditLogs(filters) {
        const page = filters?.page || 1;
        const limit = filters?.limit || 50;
        const skip = (page - 1) * limit;
        const queryBuilder = this.auditLogRepo
            .createQueryBuilder('audit')
            .leftJoinAndSelect('audit.user', 'user')
            .leftJoinAndSelect('audit.business', 'business');
        if (filters?.userId) {
            queryBuilder.andWhere('audit.userId = :userId', { userId: filters.userId });
        }
        if (filters?.businessId) {
            queryBuilder.andWhere('audit.businessId = :businessId', { businessId: filters.businessId });
        }
        if (filters?.action) {
            queryBuilder.andWhere('audit.action = :action', { action: filters.action });
        }
        if (filters?.entityType) {
            queryBuilder.andWhere('audit.entityType = :entityType', { entityType: filters.entityType });
        }
        if (filters?.startDate) {
            queryBuilder.andWhere('audit.createdAt >= :startDate', { startDate: new Date(filters.startDate) });
        }
        if (filters?.endDate) {
            queryBuilder.andWhere('audit.createdAt <= :endDate', { endDate: new Date(filters.endDate) });
        }
        queryBuilder.orderBy('audit.createdAt', 'DESC');
        queryBuilder.skip(skip).take(limit);
        const [data, total] = await queryBuilder.getManyAndCount();
        return { data, total, page, limit };
    }
    async getFailedJobs() {
        return this.failedJobRepo.find({
            order: { failedAt: 'DESC' },
        });
    }
    async retryFailedJob(jobId) {
        const job = await this.failedJobRepo.findOne({ where: { jobId } });
        if (!job) {
            throw new common_1.NotFoundException(`Failed job ${jobId} not found`);
        }
        await this.failedJobRepo.remove(job);
        this.logger.log(`Failed job ${jobId} removed for retry`);
        await this.auditLogRepo.save(this.auditLogRepo.create({
            action: 'JOB_RETRIED',
            entityType: 'FailedJob',
            entityId: jobId,
            newValue: { jobId },
        }));
        return { success: true };
    }
    async cleanFailedJobs() {
        const thirtyDaysAgo = new Date();
        thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
        const result = await this.failedJobRepo
            .createQueryBuilder()
            .delete()
            .where('failedAt < :thirtyDaysAgo', { thirtyDaysAgo })
            .execute();
        this.logger.log(`Cleaned ${result.affected} old failed jobs`);
        return { deleted: result.affected || 0 };
    }
    async getSystemSettings() {
        return this.systemSettingsRepo.find({
            order: { key: 'ASC' },
        });
    }
    async updateSystemSetting(key, value, description, isEncrypted) {
        let setting = await this.systemSettingsRepo.findOne({ where: { key } });
        if (!setting) {
            setting = this.systemSettingsRepo.create({
                key,
                value,
                description: description || null,
                isEncrypted: isEncrypted || false,
            });
        }
        else {
            setting.value = value;
            if (description !== undefined) {
                setting.description = description;
            }
            if (isEncrypted !== undefined) {
                setting.isEncrypted = isEncrypted;
            }
        }
        setting.updatedAt = new Date();
        const saved = await this.systemSettingsRepo.save(setting);
        await this.auditLogRepo.save(this.auditLogRepo.create({
            action: 'SYSTEM_SETTING_UPDATED',
            entityType: 'SystemSetting',
            entityId: saved.id,
            newValue: { key, value },
        }));
        this.logger.log(`System setting ${key} updated`);
        return saved;
    }
    async backupDatabase() {
        const dbConfig = {
            host: this.configService.get('DB_HOST', 'localhost'),
            port: this.configService.get('DB_PORT', '5432'),
            username: this.configService.get('DB_USERNAME', 'hbs_user'),
            password: this.configService.get('DB_PASSWORD', 'hbs_password'),
            database: this.configService.get('DB_NAME', 'hbs_db'),
        };
        const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
        const filename = `backup-${timestamp}.sql`;
        const backupDir = this.configService.get('BACKUP_DIR', './backups');
        const command = `set PGPASSWORD=${dbConfig.password}; pg_dump -h ${dbConfig.host} -p ${dbConfig.port} -U ${dbConfig.username} -d ${dbConfig.database} -F c -f "${backupDir}\\${filename}"`;
        try {
            await execAsync(`if not exist "${backupDir}" mkdir "${backupDir}"`);
            await execAsync(command);
            this.logger.log(`Database backup created: ${filename}`);
            await this.auditLogRepo.save(this.auditLogRepo.create({
                action: 'DATABASE_BACKUP',
                entityType: 'System',
                entityId: 'system',
                newValue: { filename },
            }));
            return { success: true, file: filename };
        }
        catch (error) {
            this.logger.error(`Database backup failed: ${error.message}`);
            throw new common_1.BadRequestException(`Backup failed: ${error.message}`);
        }
    }
    async getSystemHealth() {
        const dbStart = Date.now();
        let dbStatus = 'healthy';
        try {
            await this.businessRepo.query('SELECT 1');
        }
        catch {
            dbStatus = 'unhealthy';
        }
        const dbLatency = Date.now() - dbStart;
        let redisStatus = 'unknown';
        try {
            redisStatus = 'healthy';
        }
        catch {
            redisStatus = 'unhealthy';
        }
        const queueSize = await this.failedJobRepo.count();
        return {
            status: dbStatus === 'healthy' ? 'healthy' : 'degraded',
            timestamp: new Date().toISOString(),
            components: {
                database: { status: dbStatus, latency: dbLatency },
                redis: { status: redisStatus },
                queueSize,
            },
        };
    }
    async getMonthlyRevenueTrend() {
        const twelveMonthsAgo = new Date();
        twelveMonthsAgo.setMonth(twelveMonthsAgo.getMonth() - 12);
        twelveMonthsAgo.setDate(1);
        twelveMonthsAgo.setHours(0, 0, 0, 0);
        const rows = await this.paymentRepo
            .createQueryBuilder('payment')
            .select(['payment.createdAt as createdAt', 'payment.amount as amount'])
            .where('payment.status = :status', { status: payment_entity_1.PaymentStatus.SUCCESSFUL })
            .andWhere('payment.createdAt >= :twelveMonthsAgo', { twelveMonthsAgo })
            .getRawMany();
        const dataMap = new Map();
        for (let i = 0; i < 12; i++) {
            const d = new Date();
            d.setMonth(d.getMonth() - (11 - i));
            const key = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`;
            dataMap.set(key, { month: key, revenue: 0, count: 0 });
        }
        for (const r of rows) {
            const dt = r.createdAt instanceof Date ? r.createdAt : new Date(r.createdAt);
            if (isNaN(dt.getTime()))
                continue;
            const key = `${dt.getFullYear()}-${String(dt.getMonth() + 1).padStart(2, '0')}`;
            if (dataMap.has(key)) {
                const cur = dataMap.get(key);
                cur.revenue += Number(r.amount || 0);
                cur.count += 1;
            }
        }
        return Array.from(dataMap.values());
    }
};
exports.AdminService = AdminService;
exports.AdminService = AdminService = AdminService_1 = __decorate([
    (0, common_1.Injectable)(),
    __param(0, (0, typeorm_1.InjectRepository)(business_entity_1.Business)),
    __param(1, (0, typeorm_1.InjectRepository)(user_entity_1.User)),
    __param(2, (0, typeorm_1.InjectRepository)(role_entity_1.Role)),
    __param(3, (0, typeorm_1.InjectRepository)(permission_entity_1.Permission)),
    __param(4, (0, typeorm_1.InjectRepository)(payment_entity_1.Payment)),
    __param(5, (0, typeorm_1.InjectRepository)(subscription_entity_1.Subscription)),
    __param(6, (0, typeorm_1.InjectRepository)(subscription_plan_entity_1.SubscriptionPlan)),
    __param(7, (0, typeorm_1.InjectRepository)(router_entity_1.Router)),
    __param(8, (0, typeorm_1.InjectRepository)(location_entity_1.Location)),
    __param(9, (0, typeorm_1.InjectRepository)(commission_entity_1.Commission)),
    __param(10, (0, typeorm_1.InjectRepository)(audit_log_entity_1.AuditLog)),
    __param(11, (0, typeorm_1.InjectRepository)(api_log_entity_1.ApiLog)),
    __param(12, (0, typeorm_1.InjectRepository)(failed_job_entity_1.FailedJob)),
    __param(13, (0, typeorm_1.InjectRepository)(system_settings_entity_1.SystemSettings)),
    __param(14, (0, typeorm_1.InjectRepository)(business_settings_entity_1.BusinessSettings)),
    __param(15, (0, typeorm_1.InjectRepository)(customer_entity_1.Customer)),
    __param(18, (0, typeorm_2.InjectDataSource)()),
    __metadata("design:paramtypes", [typeorm_3.Repository,
        typeorm_3.Repository,
        typeorm_3.Repository,
        typeorm_3.Repository,
        typeorm_3.Repository,
        typeorm_3.Repository,
        typeorm_3.Repository,
        typeorm_3.Repository,
        typeorm_3.Repository,
        typeorm_3.Repository,
        typeorm_3.Repository,
        typeorm_3.Repository,
        typeorm_3.Repository,
        typeorm_3.Repository,
        typeorm_3.Repository,
        typeorm_3.Repository,
        jwt_1.JwtService,
        config_service_1.ConfigService,
        typeorm_3.DataSource])
], AdminService);
