"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 BusinessService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BusinessService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("@nestjs/typeorm");
const typeorm_2 = require("typeorm");
const business_entity_1 = require("../database/entities/business.entity");
const business_settings_entity_1 = require("../database/entities/business-settings.entity");
const user_entity_1 = require("../database/entities/user.entity");
const location_entity_1 = require("../database/entities/location.entity");
const router_entity_1 = require("../database/entities/router.entity");
const payment_entity_1 = require("../database/entities/payment.entity");
const wifi_session_entity_1 = require("../database/entities/wifi-session.entity");
const customer_entity_1 = require("../database/entities/customer.entity");
const audit_log_entity_1 = require("../database/entities/audit-log.entity");
let BusinessService = BusinessService_1 = class BusinessService {
    constructor(businessRepo, businessSettingsRepo, userRepo, locationRepo, routerRepo, paymentRepo, wifiSessionRepo, customerRepo, auditLogRepo) {
        this.businessRepo = businessRepo;
        this.businessSettingsRepo = businessSettingsRepo;
        this.userRepo = userRepo;
        this.locationRepo = locationRepo;
        this.routerRepo = routerRepo;
        this.paymentRepo = paymentRepo;
        this.wifiSessionRepo = wifiSessionRepo;
        this.customerRepo = customerRepo;
        this.auditLogRepo = auditLogRepo;
        this.logger = new common_1.Logger(BusinessService_1.name);
    }
    async getBusiness(id) {
        const business = await this.businessRepo.findOne({
            where: { id },
            relations: ['subscription'],
        });
        if (!business) {
            throw new common_1.NotFoundException(`Business ${id} not found`);
        }
        return business;
    }
    async getBusinessBySlug(slug) {
        const business = await this.businessRepo.findOne({
            where: { slug },
        });
        if (!business) {
            throw new common_1.NotFoundException(`Business with slug ${slug} not found`);
        }
        return business;
    }
    async updateBusiness(id, dto) {
        const business = await this.getBusiness(id);
        Object.assign(business, dto);
        const updated = await this.businessRepo.save(business);
        await this.auditLogRepo.save(this.auditLogRepo.create({
            businessId: id,
            action: 'BUSINESS_UPDATED',
            entityType: 'Business',
            entityId: id,
            newValue: dto,
        }));
        this.logger.log(`Business ${id} updated`);
        return updated;
    }
    async getDashboardOverview(businessId, filters) {
        const todayStart = new Date();
        todayStart.setHours(0, 0, 0, 0);
        const weekStart = new Date();
        weekStart.setDate(weekStart.getDate() - weekStart.getDay());
        weekStart.setHours(0, 0, 0, 0);
        const monthStart = new Date();
        monthStart.setDate(1);
        monthStart.setHours(0, 0, 0, 0);
        const [revenueToday, revenueThisWeek, revenueThisMonth, revenueTotal, activeCustomers, onlineUsers, expiredSessionsToday, pendingPayments, failedPayments, successfulPaymentsToday, totalDataUsed, routersOnline, routersOffline,] = await Promise.all([
            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 })
                .andWhere('payment.createdAt >= :todayStart', { todayStart })
                .getRawOne(),
            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 })
                .andWhere('payment.createdAt >= :weekStart', { weekStart })
                .getRawOne(),
            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 })
                .andWhere('payment.createdAt >= :monthStart', { monthStart })
                .getRawOne(),
            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(),
            this.customerRepo.count({ where: { businessId } }),
            this.wifiSessionRepo.count({
                where: {
                    businessId,
                    status: wifi_session_entity_1.WifiSessionStatus.ACTIVE,
                },
            }),
            this.wifiSessionRepo
                .createQueryBuilder('session')
                .where('session.businessId = :businessId', { businessId })
                .andWhere('session.status = :status', { status: wifi_session_entity_1.WifiSessionStatus.EXPIRED })
                .andWhere('session.disconnectedAt >= :todayStart', { todayStart })
                .getCount(),
            this.paymentRepo.count({
                where: { businessId, status: payment_entity_1.PaymentStatus.PENDING },
            }),
            this.paymentRepo.count({
                where: { businessId, status: payment_entity_1.PaymentStatus.FAILED },
            }),
            this.paymentRepo.count({
                where: {
                    businessId,
                    status: payment_entity_1.PaymentStatus.SUCCESSFUL,
                    createdAt: (0, typeorm_2.MoreThanOrEqual)(todayStart),
                },
            }),
            this.wifiSessionRepo
                .createQueryBuilder('session')
                .select('COALESCE(SUM(session.dataUsedMb), 0)', 'sum')
                .where('session.businessId = :businessId', { businessId })
                .andWhere('session.createdAt >= :todayStart', { todayStart })
                .getRawOne(),
            this.routerRepo.count({
                where: { businessId, isOnline: true },
            }),
            this.routerRepo.count({
                where: { businessId, isOnline: false },
            }),
        ]);
        const topPackages = await this.paymentRepo
            .createQueryBuilder('payment')
            .leftJoin('payment.package', 'package')
            .select([
            'payment.packageId as "packageId"',
            'package.name as "packageName"',
            'COUNT(payment.id) as count',
            'COALESCE(SUM(payment.amount), 0) as revenue',
        ])
            .where('payment.businessId = :businessId', { businessId })
            .andWhere('payment.status = :status', { status: payment_entity_1.PaymentStatus.SUCCESSFUL })
            .groupBy('payment.packageId')
            .addGroupBy('package.name')
            .orderBy('count', 'DESC')
            .limit(5)
            .getRawMany();
        const recentTransactions = await this.paymentRepo.find({
            where: { businessId },
            relations: ['customer', 'package'],
            order: { createdAt: 'DESC' },
            take: 10,
        });
        const revenueChart = await this.getRevenueChartData(businessId, 30);
        const packageSalesDistribution = await this.paymentRepo
            .createQueryBuilder('payment')
            .leftJoin('payment.package', 'package')
            .select([
            'payment.packageId as "packageId"',
            'package.name as "packageName"',
            'COUNT(payment.id) as count',
        ])
            .where('payment.businessId = :businessId', { businessId })
            .andWhere('payment.status = :status', { status: payment_entity_1.PaymentStatus.SUCCESSFUL })
            .groupBy('payment.packageId')
            .addGroupBy('package.name')
            .orderBy('count', 'DESC')
            .getRawMany();
        return {
            revenue: {
                today: parseFloat(revenueToday?.sum || '0'),
                thisWeek: parseFloat(revenueThisWeek?.sum || '0'),
                thisMonth: parseFloat(revenueThisMonth?.sum || '0'),
                total: parseFloat(revenueTotal?.sum || '0'),
            },
            activeCustomers,
            onlineUsers,
            expiredSessionsToday,
            pendingPayments,
            failedPayments,
            successfulPaymentsToday,
            totalDataUsedToday: parseFloat(totalDataUsed?.sum || '0'),
            routers: {
                online: routersOnline,
                offline: routersOffline,
            },
            topPackages: topPackages.map((p) => ({
                packageId: p.packageId,
                packageName: p.packageName,
                count: parseInt(p.count, 10),
                revenue: parseFloat(p.revenue),
            })),
            recentTransactions,
            revenueChart,
            packageSalesDistribution: packageSalesDistribution.map((p) => ({
                packageId: p.packageId,
                packageName: p.packageName,
                count: parseInt(p.count, 10),
            })),
        };
    }
    async getRevenueChartData(businessId, days = 30) {
        const startDate = new Date();
        startDate.setDate(startDate.getDate() - days);
        startDate.setHours(0, 0, 0, 0);
        const results = await this.paymentRepo
            .createQueryBuilder('payment')
            .select([
            'payment.createdAt as createdAt',
            'COALESCE(SUM(payment.amount), 0) as revenue',
            'COUNT(payment.id) as count',
        ])
            .where('payment.businessId = :businessId', { businessId })
            .andWhere('payment.status = :status', { status: payment_entity_1.PaymentStatus.SUCCESSFUL })
            .andWhere('payment.createdAt >= :startDate', { startDate })
            .groupBy('payment.createdAt')
            .orderBy('createdAt', 'ASC')
            .getRawMany();
        const dataMap = new Map();
        for (let i = 0; i < days; i++) {
            const d = new Date();
            d.setDate(d.getDate() - (days - 1 - i));
            const dateStr = d.toISOString().split('T')[0];
            dataMap.set(dateStr, { date: dateStr, revenue: 0, count: 0 });
        }
        for (const row of results) {
            const dt = row.createdAt instanceof Date ? row.createdAt : new Date(row.createdAt);
            const dateStr = isNaN(dt.getTime()) ? String(row.createdAt).split('T')[0] : dt.toISOString().split('T')[0];
            if (dataMap.has(dateStr)) {
                dataMap.set(dateStr, {
                    date: dateStr,
                    revenue: parseFloat(row.revenue),
                    count: parseInt(row.count, 10),
                });
            }
        }
        return Array.from(dataMap.values());
    }
    async getBusinessSettings(businessId) {
        return this.businessSettingsRepo.find({
            where: { businessId },
            order: { key: 'ASC' },
        });
    }
    async updateBusinessSettings(businessId, key, value) {
        let setting = await this.businessSettingsRepo.findOne({
            where: { businessId, key },
        });
        if (!setting) {
            setting = this.businessSettingsRepo.create({
                businessId,
                key,
                value,
            });
        }
        else {
            setting.value = value;
        }
        setting.updatedAt = new Date();
        const saved = await this.businessSettingsRepo.save(setting);
        await this.auditLogRepo.save(this.auditLogRepo.create({
            businessId,
            action: 'BUSINESS_SETTING_UPDATED',
            entityType: 'BusinessSetting',
            entityId: saved.id,
            newValue: { key, value },
        }));
        this.logger.log(`Setting ${key} updated for business ${businessId}`);
        return saved;
    }
    async verifyBusinessSuspension(businessId) {
        const business = await this.getBusiness(businessId);
        return {
            isActive: business.isActive,
            isSuspended: business.isSuspended,
            reason: business.suspendedReason || undefined,
        };
    }
    async enforceSubscriptionLimits(businessId) {
        const business = await this.getBusiness(businessId);
        const [routerCount, locationCount, staffCount, customerCount] = 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 } }),
        ]);
        return {
            routers: {
                current: routerCount,
                max: business.maxRouters,
                reached: routerCount >= business.maxRouters,
            },
            locations: {
                current: locationCount,
                max: business.maxLocations,
                reached: locationCount >= business.maxLocations,
            },
            staff: {
                current: staffCount,
                max: business.maxStaff,
                reached: staffCount >= business.maxStaff,
            },
            customers: {
                current: customerCount,
                max: business.maxCustomers,
                reached: customerCount >= business.maxCustomers,
            },
        };
    }
    async getAllBusinesses() {
        const businesses = await this.businessRepo.find({
            relations: ['subscription'],
            order: { createdAt: 'DESC' },
        });
        const result = [];
        for (const biz of businesses) {
            const [routerCount, customerCount, revenueRow] = await Promise.all([
                this.routerRepo.count({ where: { businessId: biz.id } }),
                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(),
            ]);
            result.push({
                ...biz,
                routerCount,
                customerCount,
                revenueTotal: parseFloat(revenueRow?.sum || '0'),
            });
        }
        return result;
    }
    async suspendBusiness(id, reason) {
        const business = await this.getBusiness(id);
        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: id,
            action: 'BUSINESS_SUSPENDED',
            entityType: 'Business',
            entityId: id,
            newValue: { isSuspended: true, reason },
        }));
        this.logger.log(`Business ${id} suspended: ${reason}`);
        return updated;
    }
    async unsuspendBusiness(id) {
        const business = await this.getBusiness(id);
        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: id,
            action: 'BUSINESS_UNSUSPENDED',
            entityType: 'Business',
            entityId: id,
            newValue: { isSuspended: false },
        }));
        this.logger.log(`Business ${id} unsuspended`);
        return updated;
    }
    async deleteBusiness(id) {
        const business = await this.getBusiness(id);
        business.isActive = false;
        await this.businessRepo.save(business);
        await this.auditLogRepo.save(this.auditLogRepo.create({
            businessId: id,
            action: 'BUSINESS_DELETED',
            entityType: 'Business',
            entityId: id,
            newValue: { deletedAt: new Date() },
        }));
        this.logger.log(`Business ${id} soft-deleted`);
        return { success: true };
    }
};
exports.BusinessService = BusinessService;
exports.BusinessService = BusinessService = BusinessService_1 = __decorate([
    (0, common_1.Injectable)(),
    __param(0, (0, typeorm_1.InjectRepository)(business_entity_1.Business)),
    __param(1, (0, typeorm_1.InjectRepository)(business_settings_entity_1.BusinessSettings)),
    __param(2, (0, typeorm_1.InjectRepository)(user_entity_1.User)),
    __param(3, (0, typeorm_1.InjectRepository)(location_entity_1.Location)),
    __param(4, (0, typeorm_1.InjectRepository)(router_entity_1.Router)),
    __param(5, (0, typeorm_1.InjectRepository)(payment_entity_1.Payment)),
    __param(6, (0, typeorm_1.InjectRepository)(wifi_session_entity_1.WifiSession)),
    __param(7, (0, typeorm_1.InjectRepository)(customer_entity_1.Customer)),
    __param(8, (0, typeorm_1.InjectRepository)(audit_log_entity_1.AuditLog)),
    __metadata("design:paramtypes", [typeorm_2.Repository,
        typeorm_2.Repository,
        typeorm_2.Repository,
        typeorm_2.Repository,
        typeorm_2.Repository,
        typeorm_2.Repository,
        typeorm_2.Repository,
        typeorm_2.Repository,
        typeorm_2.Repository])
], BusinessService);
