"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);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.IpWhitelistService = void 0;
const common_1 = require("@nestjs/common");
const config_1 = require("../../config");
const ip_whitelist_dto_1 = require("./ip-whitelist.dto");
let IpWhitelistService = class IpWhitelistService {
    constructor(db) {
        this.db = db;
    }
    normalizeIp(ip) {
        if (!ip)
            return '127.0.0.1';
        let cleanIp = ip.trim();
        if (cleanIp === '::1' || cleanIp === '::ffff:127.0.0.1') {
            return '127.0.0.1';
        }
        if (cleanIp.startsWith('::ffff:')) {
            cleanIp = cleanIp.substring(7);
        }
        return cleanIp;
    }
    matchIpOrCidr(clientIp, allowedPattern) {
        const pattern = allowedPattern.trim();
        const cleanClient = this.normalizeIp(clientIp);
        if (pattern === cleanClient) {
            return true;
        }
        if ((pattern === '127.0.0.1' || pattern === 'localhost') &&
            (cleanClient === '127.0.0.1' || cleanClient === '::1')) {
            return true;
        }
        if (pattern.includes('/')) {
            try {
                const [range, bitsStr] = pattern.split('/');
                const bits = parseInt(bitsStr, 10);
                if (isNaN(bits) || bits < 0 || bits > 32)
                    return false;
                const ipToInt = (addr) => {
                    return (addr
                        .split('.')
                        .reduce((acc, octet) => (acc << 8) + parseInt(octet, 10), 0) >>> 0);
                };
                const clientInt = ipToInt(cleanClient);
                const rangeInt = ipToInt(range);
                const mask = bits === 0 ? 0 : (~0 << (32 - bits)) >>> 0;
                return (clientInt & mask) === (rangeInt & mask);
            }
            catch (err) {
                config_1.logger.error(`Error matching CIDR ${pattern} against ${clientIp}`, err);
                return false;
            }
        }
        return false;
    }
    async isIpAllowed(ownerId, clientIp) {
        const activeWhitelists = await this.db.ip_whitelists.findMany({
            where: {
                owner_id: ownerId,
                is_active: true,
            },
        });
        if (!activeWhitelists || activeWhitelists.length === 0) {
            return true;
        }
        return activeWhitelists.some((record) => this.matchIpOrCidr(clientIp, record.ip_or_cidr));
    }
    async getAll(owner_id) {
        try {
            const records = await this.db.ip_whitelists.findMany({
                where: { owner_id },
                orderBy: { created_at: 'desc' },
            });
            const { data, error } = ip_whitelist_dto_1.ipWhitelistListResponseSchema.safeParse(records);
            if (error) {
                throw new config_1.ErrorResponse(error.message, common_1.HttpStatus.INTERNAL_SERVER_ERROR);
            }
            return {
                status: common_1.HttpStatus.OK,
                message: 'IP whitelist retrieved successfully',
                data,
            };
        }
        catch (error) {
            config_1.logger.error('Error fetching IP whitelists', error);
            if (error instanceof config_1.ErrorResponse)
                throw error;
            throw new config_1.ErrorResponse(error, common_1.HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
    async create(data, owner_id) {
        try {
            const newEntry = await this.db.ip_whitelists.create({
                data: {
                    owner_id,
                    label: data.label,
                    ip_or_cidr: data.ip_or_cidr.trim(),
                    is_active: data.is_active ?? true,
                },
            });
            const { data: parsedData, error } = ip_whitelist_dto_1.ipWhitelistResponseSchema.safeParse(newEntry);
            if (error) {
                throw new config_1.ErrorResponse(error.message, common_1.HttpStatus.INTERNAL_SERVER_ERROR);
            }
            return {
                status: common_1.HttpStatus.CREATED,
                message: 'IP whitelist entry added successfully',
                data: parsedData,
            };
        }
        catch (error) {
            config_1.logger.error('Error creating IP whitelist entry', error);
            if (error instanceof config_1.ErrorResponse)
                throw error;
            throw new config_1.ErrorResponse(error, common_1.HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
    async update(id, data, owner_id) {
        try {
            const existing = await this.db.ip_whitelists.findFirst({
                where: { id, owner_id },
            });
            if (!existing) {
                throw new config_1.ErrorResponse('IP whitelist entry not found', common_1.HttpStatus.NOT_FOUND);
            }
            const updated = await this.db.ip_whitelists.update({
                where: { id },
                data: {
                    ...(data.label !== undefined ? { label: data.label } : {}),
                    ...(data.ip_or_cidr !== undefined ? { ip_or_cidr: data.ip_or_cidr.trim() } : {}),
                    ...(data.is_active !== undefined ? { is_active: data.is_active } : {}),
                },
            });
            const { data: parsedData, error } = ip_whitelist_dto_1.ipWhitelistResponseSchema.safeParse(updated);
            if (error) {
                throw new config_1.ErrorResponse(error.message, common_1.HttpStatus.INTERNAL_SERVER_ERROR);
            }
            return {
                status: common_1.HttpStatus.OK,
                message: 'IP whitelist entry updated successfully',
                data: parsedData,
            };
        }
        catch (error) {
            config_1.logger.error('Error updating IP whitelist entry', error);
            if (error instanceof config_1.ErrorResponse)
                throw error;
            throw new config_1.ErrorResponse(error, common_1.HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
    async delete(id, owner_id) {
        try {
            const existing = await this.db.ip_whitelists.findFirst({
                where: { id, owner_id },
            });
            if (!existing) {
                throw new config_1.ErrorResponse('IP whitelist entry not found', common_1.HttpStatus.NOT_FOUND);
            }
            await this.db.ip_whitelists.delete({
                where: { id },
            });
            return {
                status: common_1.HttpStatus.OK,
                message: 'IP whitelist entry deleted successfully',
            };
        }
        catch (error) {
            config_1.logger.error('Error deleting IP whitelist entry', error);
            if (error instanceof config_1.ErrorResponse)
                throw error;
            throw new config_1.ErrorResponse(error, common_1.HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
};
exports.IpWhitelistService = IpWhitelistService;
exports.IpWhitelistService = IpWhitelistService = __decorate([
    (0, common_1.Injectable)(),
    __metadata("design:paramtypes", [config_1.DatabaseService])
], IpWhitelistService);
//# sourceMappingURL=ip-whitelist.service.js.map