"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); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TokenService = void 0;
const api_locale_1 = require("@hed-hog/api-locale");
const api_prisma_1 = require("@hed-hog/api-prisma");
const common_1 = require("@nestjs/common");
const jwt_1 = require("@nestjs/jwt");
const security_service_1 = require("../security/security.service");
const setting_service_1 = require("../setting/setting.service");
let TokenService = class TokenService {
    constructor(prisma, jwt, security, setting) {
        this.prisma = prisma;
        this.jwt = jwt;
        this.security = security;
        this.setting = setting;
    }
    async verify(locale, token) {
        try {
            const payload = await this.jwt.verifyAsync(token, {
                secret: this.security.getJwtSecret(),
            });
            // Verify session is not revoked (only if prisma is available)
            if (payload.sessionId && this.prisma) {
                try {
                    const session = await this.prisma.user_session.findUnique({
                        where: { id: payload.sessionId },
                        select: { revoked_at: true, expires_at: true }
                    });
                    if (!session || session.revoked_at !== null || session.expires_at <= new Date()) {
                        throw new common_1.UnauthorizedException((0, api_locale_1.getLocaleText)('sessionRevoked', locale, 'Session has been revoked.'));
                    }
                }
                catch (sessionError) {
                    // If it's an Unauthorized error from revoked session, rethrow it
                    if (sessionError instanceof common_1.UnauthorizedException) {
                        throw sessionError;
                    }
                    // Otherwise, log the error but allow auth to continue
                    console.error('Session validation error:', sessionError);
                }
            }
            return payload;
        }
        catch (error) {
            // Return 401 for JWT errors (expired, invalid, etc.)
            throw new common_1.UnauthorizedException(error.message || (0, api_locale_1.getLocaleText)('accessDenied', locale, 'Access denied.'));
        }
    }
    async createAccessToken(payload) {
        return this.jwt.signAsync(payload, {
            secret: this.security.getJwtSecret(),
        });
    }
    async createOpaqueToken(size = 64) {
        return this.security.randomOpaque(size);
    }
    normalizeCookieDomain(value) {
        const normalized = value === null || value === void 0 ? void 0 : value.trim();
        if (!normalized) {
            return undefined;
        }
        const host = normalized
            .replace(/^https?:\/\//i, '')
            .split('/')[0]
            .split(':')[0]
            .trim();
        if (!host || host === 'localhost' || /^\d{1,3}(\.\d{1,3}){3}$/.test(host)) {
            return undefined;
        }
        return host;
    }
    async getCookieDomain() {
        const explicitDomain = this.normalizeCookieDomain(process.env.COOKIE_DOMAIN);
        if (explicitDomain) {
            return explicitDomain;
        }
        const settings = await this.setting.getSettingValues([
            'api-url'
        ]);
        return this.normalizeCookieDomain(settings['api-url']);
    }
    async removeRefreshTokenCookie(res) {
        const domain = await this.getCookieDomain();
        const isLocalhost = !domain || domain === 'localhost';
        const cookieOptions = {
            httpOnly: true,
            sameSite: isLocalhost ? 'lax' : 'none',
        };
        if (!isLocalhost) {
            cookieOptions.secure = true;
            cookieOptions.domain = domain;
        }
        res.clearCookie('rt', cookieOptions);
    }
    async setRefreshTokenCookie(locale, res, token, expires_at) {
        const domain = await this.getCookieDomain();
        const isLocalhost = !domain || domain === 'localhost';
        const maxAge = expires_at.getTime() - Date.now();
        const cookieOptions = {
            httpOnly: true,
            sameSite: isLocalhost ? 'lax' : 'none',
            maxAge,
        };
        if (!isLocalhost) {
            cookieOptions.secure = true;
            cookieOptions.domain = domain;
        }
        res.cookie('rt', token, cookieOptions);
    }
    async createMfaChallengeToken(payload) {
        return this.jwt.signAsync(payload, {
            secret: this.security.getJwtSecret(),
            expiresIn: '10m',
        });
    }
    async verifyMfaChallengeToken(token) {
        try {
            const payload = await this.jwt.verifyAsync(token, {
                secret: this.security.getJwtSecret()
            });
            return {
                userId: payload.userId,
                ipAddress: payload.ipAddress,
                userAgent: payload.userAgent,
                email: payload.email
            };
        }
        catch (error) {
            throw new common_1.ForbiddenException('Invalid or expired MFA token');
        }
    }
    async decodeExpiredToken(token) {
        try {
            return await this.jwt.verifyAsync(token, {
                secret: this.security.getJwtSecret(),
                ignoreExpiration: true,
            });
        }
        catch (error) {
            throw new common_1.UnauthorizedException('Invalid token');
        }
    }
};
exports.TokenService = TokenService;
exports.TokenService = TokenService = __decorate([
    (0, common_1.Injectable)(),
    __param(1, (0, common_1.Inject)((0, common_1.forwardRef)(() => jwt_1.JwtService))),
    __param(2, (0, common_1.Inject)((0, common_1.forwardRef)(() => security_service_1.SecurityService))),
    __param(3, (0, common_1.Inject)((0, common_1.forwardRef)(() => setting_service_1.SettingService))),
    __metadata("design:paramtypes", [api_prisma_1.PrismaService,
        jwt_1.JwtService,
        security_service_1.SecurityService,
        setting_service_1.SettingService])
], TokenService);
//# sourceMappingURL=token.service.js.map