"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 LocationsService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.LocationsService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("@nestjs/typeorm");
const typeorm_2 = require("typeorm");
const location_entity_1 = require("../database/entities/location.entity");
const router_entity_1 = require("../database/entities/router.entity");
const business_entity_1 = require("../database/entities/business.entity");
const package_router_assignment_entity_1 = require("../database/entities/package-router-assignment.entity");
const audit_log_entity_1 = require("../database/entities/audit-log.entity");
const wifi_session_entity_1 = require("../database/entities/wifi-session.entity");
const payment_entity_1 = require("../database/entities/payment.entity");
let LocationsService = LocationsService_1 = class LocationsService {
    constructor(locationRepo, routerRepo, businessRepo, packageRouterAssignmentRepo, auditLogRepo, wifiSessionRepo, paymentRepo) {
        this.locationRepo = locationRepo;
        this.routerRepo = routerRepo;
        this.businessRepo = businessRepo;
        this.packageRouterAssignmentRepo = packageRouterAssignmentRepo;
        this.auditLogRepo = auditLogRepo;
        this.wifiSessionRepo = wifiSessionRepo;
        this.paymentRepo = paymentRepo;
        this.logger = new common_1.Logger(LocationsService_1.name);
    }
    async findAll(businessId) {
        return this.locationRepo.find({
            where: { businessId, isActive: true },
            order: { createdAt: 'DESC' },
        });
    }
    async findOne(id, businessId) {
        const location = await this.locationRepo.findOne({
            where: { id, businessId },
        });
        if (!location) {
            throw new common_1.NotFoundException(`Location ${id} not found`);
        }
        const routers = await this.routerRepo.find({
            where: { locationId: id, businessId, isActive: true },
            order: { name: 'ASC' },
        });
        const routerIds = routers.map((r) => r.id);
        let assignments = [];
        if (routerIds.length > 0) {
            assignments = await this.packageRouterAssignmentRepo.find({
                where: { routerId: (0, typeorm_2.In)(routerIds) },
                relations: ['package'],
            });
        }
        const uniquePackages = new Map();
        for (const assignment of assignments) {
            if (assignment.package && !uniquePackages.has(assignment.package.id)) {
                uniquePackages.set(assignment.package.id, {
                    id: assignment.package.id,
                    name: assignment.package.name,
                    type: assignment.package.type,
                    priceKes: assignment.package.priceKes,
                    isActive: assignment.package.isActive,
                });
            }
        }
        return {
            location,
            routers,
            packages: Array.from(uniquePackages.values()),
        };
    }
    async create(dto, businessId) {
        const business = await this.businessRepo.findOne({
            where: { id: businessId },
        });
        if (!business) {
            throw new common_1.NotFoundException(`Business ${businessId} not found`);
        }
        const activeCount = await this.locationRepo.count({
            where: { businessId, isActive: true },
        });
        if (activeCount >= business.maxLocations) {
            throw new common_1.BadRequestException(`Location limit reached (${business.maxLocations}). Please upgrade your subscription to add more locations.`);
        }
        const location = this.locationRepo.create({
            businessId,
            name: dto.name,
            address: dto.address || undefined,
            city: dto.city || undefined,
            state: dto.state || undefined,
            country: dto.country || 'Kenya',
            latitude: dto.latitude || undefined,
            longitude: dto.longitude || undefined,
            settings: dto.settings || undefined,
            isActive: true,
        });
        const saved = await this.locationRepo.save(location);
        await this.auditLogRepo.save(this.auditLogRepo.create({
            businessId,
            action: 'LOCATION_CREATED',
            entityType: 'Location',
            entityId: saved.id,
            newValue: {
                name: saved.name,
                city: saved.city,
                country: saved.country,
            },
        }));
        this.logger.log(`Location ${saved.id} (${saved.name}) created for business ${businessId}`);
        return saved;
    }
    async update(id, dto, businessId) {
        const location = await this.locationRepo.findOne({
            where: { id, businessId },
        });
        if (!location) {
            throw new common_1.NotFoundException(`Location ${id} not found`);
        }
        if (dto.name !== undefined)
            location.name = dto.name;
        if (dto.address !== undefined)
            location.address = dto.address;
        if (dto.city !== undefined)
            location.city = dto.city;
        if (dto.state !== undefined)
            location.state = dto.state;
        if (dto.country !== undefined)
            location.country = dto.country;
        if (dto.latitude !== undefined)
            location.latitude = dto.latitude;
        if (dto.longitude !== undefined)
            location.longitude = dto.longitude;
        if (dto.settings !== undefined)
            location.settings = dto.settings;
        if (dto.isActive !== undefined)
            location.isActive = dto.isActive;
        const saved = await this.locationRepo.save(location);
        await this.auditLogRepo.save(this.auditLogRepo.create({
            businessId,
            action: 'LOCATION_UPDATED',
            entityType: 'Location',
            entityId: saved.id,
            newValue: dto,
        }));
        this.logger.log(`Location ${id} updated`);
        return saved;
    }
    async delete(id, businessId) {
        const location = await this.locationRepo.findOne({
            where: { id, businessId },
        });
        if (!location) {
            throw new common_1.NotFoundException(`Location ${id} not found`);
        }
        const activeRouters = await this.routerRepo.count({
            where: { locationId: id, isActive: true },
        });
        if (activeRouters > 0) {
            throw new common_1.BadRequestException(`Cannot delete location with ${activeRouters} active router(s). Remove or reassign routers first.`);
        }
        location.isActive = false;
        await this.locationRepo.save(location);
        await this.auditLogRepo.save(this.auditLogRepo.create({
            businessId,
            action: 'LOCATION_DELETED',
            entityType: 'Location',
            entityId: id,
            previousValue: { name: location.name },
            newValue: { isActive: false },
        }));
        this.logger.log(`Location ${id} soft-deleted`);
    }
    async assignRouter(locationId, routerId, businessId) {
        const location = await this.locationRepo.findOne({
            where: { id: locationId, businessId, isActive: true },
        });
        if (!location) {
            throw new common_1.NotFoundException(`Location ${locationId} not found`);
        }
        const router = await this.routerRepo.findOne({
            where: { id: routerId, businessId, isActive: true },
        });
        if (!router) {
            throw new common_1.NotFoundException(`Router ${routerId} not found`);
        }
        router.locationId = locationId;
        const saved = await this.routerRepo.save(router);
        await this.auditLogRepo.save(this.auditLogRepo.create({
            businessId,
            action: 'ROUTER_ASSIGNED_TO_LOCATION',
            entityType: 'Router',
            entityId: routerId,
            newValue: {
                locationId,
                locationName: location.name,
                routerName: router.name,
            },
        }));
        this.logger.log(`Router ${routerId} assigned to location ${locationId}`);
        return saved;
    }
    async removeRouter(locationId, routerId) {
        const router = await this.routerRepo.findOne({
            where: { id: routerId, locationId, isActive: true },
        });
        if (!router) {
            throw new common_1.NotFoundException(`Router ${routerId} not found at location ${locationId}`);
        }
        router.locationId = null;
        const saved = await this.routerRepo.save(router);
        await this.auditLogRepo.save(this.auditLogRepo.create({
            businessId: router.businessId,
            action: 'ROUTER_REMOVED_FROM_LOCATION',
            entityType: 'Router',
            entityId: routerId,
            previousValue: { locationId },
            newValue: { locationId: null },
        }));
        this.logger.log(`Router ${routerId} removed from location ${locationId}`);
        return saved;
    }
    async getLocationStats(locationId, businessId) {
        const location = await this.locationRepo.findOne({
            where: { id: locationId, businessId },
        });
        if (!location) {
            throw new common_1.NotFoundException(`Location ${locationId} not found`);
        }
        const routers = await this.routerRepo.find({
            where: { locationId, businessId },
            select: ['id'],
        });
        const routerIds = routers.map((r) => r.id);
        if (routerIds.length === 0) {
            return {
                totalSessions: 0,
                activeSessions: 0,
                totalRevenue: 0,
                routerCount: 0,
            };
        }
        const [totalSessions, activeSessions, payments] = await Promise.all([
            this.wifiSessionRepo.count({
                where: { routerId: (0, typeorm_2.In)(routerIds) },
            }),
            this.wifiSessionRepo.count({
                where: {
                    routerId: (0, typeorm_2.In)(routerIds),
                    status: (0, typeorm_2.In)([wifi_session_entity_1.WifiSessionStatus.ACTIVE, wifi_session_entity_1.WifiSessionStatus.PAUSED]),
                },
            }),
            this.paymentRepo.find({
                where: {
                    routerId: (0, typeorm_2.In)(routerIds),
                    status: payment_entity_1.PaymentStatus.SUCCESSFUL,
                },
                select: ['amount'],
            }),
        ]);
        const totalRevenue = payments.reduce((sum, p) => sum + Number(p.amount), 0);
        return {
            totalSessions,
            activeSessions,
            totalRevenue,
            routerCount: routerIds.length,
        };
    }
    async getLocationRouters(locationId, businessId) {
        const location = await this.locationRepo.findOne({
            where: { id: locationId, businessId, isActive: true },
        });
        if (!location) {
            throw new common_1.NotFoundException(`Location ${locationId} not found`);
        }
        return this.routerRepo.find({
            where: { locationId, businessId, isActive: true },
            order: { name: 'ASC' },
        });
    }
};
exports.LocationsService = LocationsService;
exports.LocationsService = LocationsService = LocationsService_1 = __decorate([
    (0, common_1.Injectable)(),
    __param(0, (0, typeorm_1.InjectRepository)(location_entity_1.Location)),
    __param(1, (0, typeorm_1.InjectRepository)(router_entity_1.Router)),
    __param(2, (0, typeorm_1.InjectRepository)(business_entity_1.Business)),
    __param(3, (0, typeorm_1.InjectRepository)(package_router_assignment_entity_1.PackageRouterAssignment)),
    __param(4, (0, typeorm_1.InjectRepository)(audit_log_entity_1.AuditLog)),
    __param(5, (0, typeorm_1.InjectRepository)(wifi_session_entity_1.WifiSession)),
    __param(6, (0, typeorm_1.InjectRepository)(payment_entity_1.Payment)),
    __metadata("design:paramtypes", [typeorm_2.Repository,
        typeorm_2.Repository,
        typeorm_2.Repository,
        typeorm_2.Repository,
        typeorm_2.Repository,
        typeorm_2.Repository,
        typeorm_2.Repository])
], LocationsService);
