"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.AuthController = void 0;
const common_1 = require("@nestjs/common");
const auth_service_1 = require("../services/auth.service");
const verify_2fa_request_dto_1 = require("../dto/requests/verify-2fa.request.dto");
const refresh_token_request_dto_1 = require("../dto/requests/refresh-token.request.dto");
const swagger_1 = require("@nestjs/swagger");
const swagger_2 = require("@nestjs/swagger");
const cookie_service_1 = require("../services/cookie.service");
const auth_config_service_1 = require("../../core/services/auth-config.service");
const auth_response_dto_1 = require("../dto/responses/auth.response.dto");
const auth_cookie_response_dto_1 = require("../dto/responses/auth-cookie.response.dto");
const signup_request_dto_1 = require("../dto/requests/signup.request.dto");
const login_request_dto_1 = require("../dto/requests/login.request.dto");
const request_context_1 = require("../../request-context/request-context");
const core_1 = require("../../core");
const forgot_password_request_dto_1 = require("../dto/requests/forgot-password.request.dto");
const reset_password_request_dto_1 = require("../dto/requests/reset-password.request.dto");
const auth_guard_1 = require("../guards/auth.guard");
const verify_forgot_password_otp_request_dto_1 = require("../dto/requests/verify-forgot-password-otp-request-dto");
const reset_password_with_token_request_dto_1 = require("../dto/requests/reset-password-with-token.request.dto");
const verify_otp_response_dto_1 = require("../dto/responses/verify-otp.response.dto");
const change_password_request_dto_1 = require("../dto/requests/change-password.request.dto");
const send_email_verification_request_dto_1 = require("../dto/requests/send-email-verification.request.dto");
const verify_email_request_dto_1 = require("../dto/requests/verify-email.request.dto");
const client_config_service_1 = require("../services/client-config.service");
const client_config_response_dto_1 = require("../dto/responses/client-config.response.dto");
const auth_constants_1 = require("../../auth.constants");
let AuthController = class AuthController {
    authService;
    cookieService;
    authConfig;
    clientConfigService;
    constructor(authService, cookieService, authConfig, clientConfigService) {
        this.authService = authService;
        this.cookieService = cookieService;
        this.authConfig = authConfig;
        this.clientConfigService = clientConfigService;
    }
    isUsingCookies() {
        const config = this.authConfig.getConfig();
        return config.accessTokenType === 'cookie';
    }
    handleAuthResponse(res, authResult, successMessage = 'Authentication successful') {
        if (this.isUsingCookies()) {
            this.cookieService.setTokens(res, authResult.accessToken, authResult.refreshToken);
            res.status(200).json({
                message: successMessage,
                isRequiresMfa: authResult.isRequiresMfa
            });
        }
        else {
            res.status(200).json({
                message: successMessage,
                accessToken: authResult.accessToken,
                refreshToken: authResult.refreshToken,
                isRequiresMfa: authResult.isRequiresMfa
            });
        }
    }
    handle2faResponse(res, authResult) {
        if (authResult.trustToken) {
            const trustCookieName = auth_config_service_1.AuthConfigService.getOptions().mfa?.trustDeviceStorageName || auth_constants_1.NEST_AUTH_TRUST_DEVICE_KEY;
            const duration = auth_config_service_1.AuthConfigService.getOptions().mfa?.trustedDeviceDuration || '30d';
            const ms = require('ms');
            const maxAge = typeof duration === 'string' ? ms(duration) : duration;
            res.cookie(trustCookieName, authResult.trustToken, {
                httpOnly: true,
                secure: process.env.NODE_ENV === 'production',
                sameSite: 'lax',
                path: '/',
                maxAge,
            });
        }
        if (this.isUsingCookies()) {
            this.cookieService.setTokens(res, authResult.accessToken, authResult.refreshToken);
            res.status(200).json({
                message: '2FA verification successful',
                trustToken: authResult.trustToken
            });
        }
        else {
            res.status(200).json({
                message: '2FA verification successful',
                accessToken: authResult.accessToken,
                refreshToken: authResult.refreshToken,
                trustToken: authResult.trustToken
            });
        }
    }
    async signup(input, res) {
        const response = await this.authService.signup(input);
        this.handleAuthResponse(res, response, 'Signup successful');
    }
    async login(input, res) {
        const response = await this.authService.login(input);
        this.handleAuthResponse(res, response, 'Login successful');
    }
    async refreshToken(input, res) {
        const response = await this.authService.refreshToken(input.refreshToken);
        this.handleAuthResponse(res, { ...response, isRequiresMfa: false }, 'Token refreshed successfully');
    }
    async send2faCode(method) {
        const user = request_context_1.RequestContext.currentUser();
        await this.authService.send2faCode(user.id, method);
        return { message: '2FA code sent successfully' };
    }
    async verify2fa(input, res) {
        const response = await this.authService.verify2fa(input);
        this.handle2faResponse(res, response);
    }
    async logout(res) {
        await this.authService.logout();
        if (this.isUsingCookies()) {
            this.cookieService.clearCookies(res);
        }
        res.status(200).json({ message: 'Logged out successfully' });
    }
    async logoutAll() {
        const user = request_context_1.RequestContext.currentUser();
        await this.authService.logoutAll(user.id);
        return { message: 'Logged out from all devices successfully' };
    }
    async changePassword(input, res) {
        const response = await this.authService.changePassword(input);
        this.handleAuthResponse(res, response, 'Password updated successfully');
    }
    async forgotPassword(input) {
        await this.authService.forgotPassword(input);
        return { message: 'If the account exists, a password reset code has been sent' };
    }
    async verifyForgotPasswordOtp(input) {
        return await this.authService.verifyForgotPasswordOtp(input);
    }
    async resetPassword(input) {
        await this.authService.resetPassword(input);
        return { message: 'Password reset successfully' };
    }
    async resetPasswordWithToken(input) {
        await this.authService.resetPasswordWithToken(input);
        return { message: 'Password reset successfully' };
    }
    async getUser() {
        return await this.authService.getUser();
    }
    async sendEmailVerification(input) {
        return await this.authService.sendEmailVerification(input);
    }
    async verifyEmail(input) {
        return await this.authService.verifyEmail(input);
    }
    async getClientConfig() {
        return await this.clientConfigService.getClientConfig();
    }
    async ssoCallback(provider, data, res) {
        const jsonData = JSON.stringify(data);
        const escapedData = jsonData.replace(/</g, '\\u003c').replace(/>/g, '\\u003e');
        const html = `<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SSO Callback</title>
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            margin: 0;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        }
        .container {
            background: white;
            padding: 2rem;
            border-radius: 8px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
            text-align: center;
            max-width: 400px;
        }
        .spinner {
            border: 3px solid #f3f3f3;
            border-top: 3px solid #667eea;
            border-radius: 50%;
            width: 40px;
            height: 40px;
            animation: spin 1s linear infinite;
            margin: 0 auto 1rem;
        }
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        .message {
            color: #333;
            margin-top: 1rem;
        }
        .error {
            color: #dc3545;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="spinner"></div>
        <div class="message" id="message">Processing...</div>
    </div>
    <script>
        (function() {
            const data = ${escapedData};

            // Post message to parent window
            if (window.opener) {
                window.opener.postMessage({
                    type: 'nest-auth-sso-callback',
                    ...data
                }, '*');

                // Auto-close immediately
                window.close();
            } else if (window.parent && window.parent !== window) {
                // Iframe context
                window.parent.postMessage({
                    type: 'nest-auth-sso-callback',
                    ...data
                }, '*');
                // Note: Can't close iframe from inside
            } else {
                // No parent window, show message
                document.getElementById('message').textContent = data.success
                    ? 'Success! You can close this window.'
                    : 'Error: ' + (data.errorDescription || data.error);
                document.getElementById('message').className = data.success ? 'message' : 'message error';
            }
        })();
    </script>
</body>
</html>`;
        res.setHeader('Content-Type', 'text/html');
        res.status(200).send(html);
    }
};
exports.AuthController = AuthController;
__decorate([
    (0, swagger_2.ApiOperation)({
        summary: 'Signup',
        description: 'Register a new user. Response format depends on accessTokenType configuration:\n' +
            '- Header mode (default): Returns tokens in response body\n' +
            '- Cookie mode: Sets tokens in HTTP-only cookies and returns success message'
    }),
    (0, swagger_1.ApiResponse)({ status: 200, type: auth_response_dto_1.AuthWithTokensResponseDto, description: 'Header mode: Returns message + tokens in body' }),
    (0, swagger_1.ApiResponse)({ status: 200, type: auth_cookie_response_dto_1.AuthCookieResponseDto, description: 'Cookie mode: Returns message only, tokens in cookies' }),
    (0, common_1.HttpCode)(200),
    (0, common_1.Post)('signup'),
    __param(0, (0, common_1.Body)()),
    __param(1, (0, common_1.Res)()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [signup_request_dto_1.SignupRequestDto, Object]),
    __metadata("design:returntype", Promise)
], AuthController.prototype, "signup", null);
__decorate([
    (0, swagger_2.ApiOperation)({
        summary: 'Login',
        description: 'Authenticate user. Response format depends on accessTokenType configuration:\n' +
            '- Header mode (default): Returns tokens in response body\n' +
            '- Cookie mode: Sets tokens in HTTP-only cookies and returns success message'
    }),
    (0, swagger_1.ApiResponse)({ status: 200, type: auth_response_dto_1.AuthWithTokensResponseDto, description: 'Header mode: Returns message + tokens in body' }),
    (0, swagger_1.ApiResponse)({ status: 200, type: auth_cookie_response_dto_1.AuthCookieResponseDto, description: 'Cookie mode: Returns message only, tokens in cookies' }),
    (0, common_1.HttpCode)(200),
    (0, common_1.Post)('login'),
    __param(0, (0, common_1.Body)()),
    __param(1, (0, common_1.Res)()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [login_request_dto_1.LoginRequestDto, Object]),
    __metadata("design:returntype", Promise)
], AuthController.prototype, "login", null);
__decorate([
    (0, swagger_2.ApiOperation)({
        summary: 'Refresh Token',
        description: 'Refresh access token. Response format depends on accessTokenType configuration:\n' +
            '- Header mode (default): Returns new tokens in response body\n' +
            '- Cookie mode: Sets new tokens in HTTP-only cookies and returns success message'
    }),
    (0, swagger_1.ApiResponse)({ status: 200, type: auth_response_dto_1.AuthWithTokensResponseDto, description: 'Header mode: Returns message + tokens in body' }),
    (0, swagger_1.ApiResponse)({ status: 200, type: auth_cookie_response_dto_1.AuthCookieResponseDto, description: 'Cookie mode: Returns message only, tokens in cookies' }),
    (0, common_1.HttpCode)(200),
    (0, common_1.Post)('refresh-token'),
    __param(0, (0, common_1.Body)()),
    __param(1, (0, common_1.Res)()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [refresh_token_request_dto_1.RefreshTokenRequestDto, Object]),
    __metadata("design:returntype", Promise)
], AuthController.prototype, "refreshToken", null);
__decorate([
    (0, swagger_2.ApiOperation)({ summary: 'Send 2FA Code' }),
    (0, swagger_1.ApiResponse)({ status: 200, type: core_1.MessageResponseDto }),
    (0, common_1.HttpCode)(200),
    (0, common_1.Post)('send-2fa-code'),
    (0, core_1.SkipMfa)(),
    (0, common_1.UseGuards)(auth_guard_1.NestAuthAuthGuard),
    __param(0, (0, common_1.Body)('method')),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String]),
    __metadata("design:returntype", Promise)
], AuthController.prototype, "send2faCode", null);
__decorate([
    (0, swagger_2.ApiOperation)({
        summary: 'Verify 2FA',
        description: 'Verify two-factor authentication. Response format depends on accessTokenType configuration:\n' +
            '- Header mode (default): Returns tokens in response body\n' +
            '- Cookie mode: Sets tokens in HTTP-only cookies and returns success message'
    }),
    (0, swagger_1.ApiResponse)({ status: 200, type: auth_response_dto_1.Verify2faWithTokensResponseDto, description: 'Header mode: Returns message + tokens in body' }),
    (0, swagger_1.ApiResponse)({ status: 200, type: auth_cookie_response_dto_1.AuthCookieResponseDto, description: 'Cookie mode: Returns message only, tokens in cookies' }),
    (0, common_1.HttpCode)(200),
    (0, common_1.Post)('verify-2fa'),
    (0, core_1.SkipMfa)(),
    (0, common_1.UseGuards)(auth_guard_1.NestAuthAuthGuard),
    __param(0, (0, common_1.Body)()),
    __param(1, (0, common_1.Res)()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [verify_2fa_request_dto_1.Verify2faRequestDto, Object]),
    __metadata("design:returntype", Promise)
], AuthController.prototype, "verify2fa", null);
__decorate([
    (0, swagger_2.ApiOperation)({ summary: 'Logout' }),
    (0, swagger_1.ApiResponse)({ status: 200, type: core_1.MessageResponseDto }),
    (0, common_1.HttpCode)(200),
    (0, common_1.Post)('logout'),
    (0, core_1.SkipMfa)(),
    (0, common_1.UseGuards)(auth_guard_1.NestAuthAuthGuard),
    __param(0, (0, common_1.Res)()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], AuthController.prototype, "logout", null);
__decorate([
    (0, swagger_2.ApiOperation)({ summary: 'Logout All' }),
    (0, swagger_1.ApiResponse)({ status: 200, type: core_1.MessageResponseDto }),
    (0, common_1.HttpCode)(200),
    (0, common_1.Post)('logout-all'),
    (0, core_1.SkipMfa)(),
    (0, common_1.UseGuards)(auth_guard_1.NestAuthAuthGuard),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", Promise)
], AuthController.prototype, "logoutAll", null);
__decorate([
    (0, swagger_2.ApiOperation)({ summary: 'Change Password' }),
    (0, swagger_1.ApiResponse)({ status: 200, type: auth_response_dto_1.AuthWithTokensResponseDto }),
    (0, common_1.HttpCode)(200),
    (0, common_1.Post)('change-password'),
    (0, core_1.SkipMfa)(),
    (0, common_1.UseGuards)(auth_guard_1.NestAuthAuthGuard),
    __param(0, (0, common_1.Body)()),
    __param(1, (0, common_1.Res)()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [change_password_request_dto_1.ChangePasswordRequestDto, Object]),
    __metadata("design:returntype", Promise)
], AuthController.prototype, "changePassword", null);
__decorate([
    (0, swagger_2.ApiOperation)({ summary: 'Forgot Password' }),
    (0, swagger_1.ApiResponse)({ status: 200, type: core_1.MessageResponseDto }),
    (0, common_1.HttpCode)(200),
    (0, common_1.Post)('forgot-password'),
    (0, core_1.SkipMfa)(),
    __param(0, (0, common_1.Body)()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [forgot_password_request_dto_1.ForgotPasswordRequestDto]),
    __metadata("design:returntype", Promise)
], AuthController.prototype, "forgotPassword", null);
__decorate([
    (0, swagger_2.ApiOperation)({ summary: 'Verify Forgot Password OTP and get reset token' }),
    (0, swagger_1.ApiResponse)({ status: 200, type: verify_otp_response_dto_1.VerifyOtpResponseDto }),
    (0, common_1.HttpCode)(200),
    (0, common_1.Post)('verify-forgot-password-otp'),
    (0, core_1.SkipMfa)(),
    __param(0, (0, common_1.Body)()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [verify_forgot_password_otp_request_dto_1.VerifyForgotPasswordOtpRequestDto]),
    __metadata("design:returntype", Promise)
], AuthController.prototype, "verifyForgotPasswordOtp", null);
__decorate([
    (0, swagger_2.ApiOperation)({ summary: 'Reset Password (Legacy - using OTP)' }),
    (0, swagger_1.ApiResponse)({ status: 200, type: core_1.MessageResponseDto }),
    (0, common_1.HttpCode)(200),
    (0, common_1.Post)('reset-password'),
    (0, core_1.SkipMfa)(),
    __param(0, (0, common_1.Body)()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [reset_password_request_dto_1.ResetPasswordRequestDto]),
    __metadata("design:returntype", Promise)
], AuthController.prototype, "resetPassword", null);
__decorate([
    (0, swagger_2.ApiOperation)({ summary: 'Reset Password with Token' }),
    (0, swagger_1.ApiResponse)({ status: 200, type: core_1.MessageResponseDto }),
    (0, common_1.HttpCode)(200),
    (0, common_1.Post)('reset-password-with-token'),
    (0, core_1.SkipMfa)(),
    __param(0, (0, common_1.Body)()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [reset_password_with_token_request_dto_1.ResetPasswordWithTokenRequestDto]),
    __metadata("design:returntype", Promise)
], AuthController.prototype, "resetPasswordWithToken", null);
__decorate([
    (0, swagger_2.ApiOperation)({ summary: 'Get Logged In User' }),
    (0, swagger_1.ApiResponse)({ status: 200, type: auth_response_dto_1.UserResponseDto }),
    (0, common_1.UseGuards)(auth_guard_1.NestAuthAuthGuard),
    (0, common_1.Get)('user'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", Promise)
], AuthController.prototype, "getUser", null);
__decorate([
    (0, swagger_2.ApiOperation)({ summary: 'Send Email Verification' }),
    (0, swagger_1.ApiResponse)({ status: 200, type: core_1.MessageResponseDto }),
    (0, common_1.HttpCode)(200),
    (0, common_1.Post)('send-email-verification'),
    (0, core_1.SkipMfa)(),
    (0, common_1.UseGuards)(auth_guard_1.NestAuthAuthGuard),
    __param(0, (0, common_1.Body)()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [send_email_verification_request_dto_1.SendEmailVerificationRequestDto]),
    __metadata("design:returntype", Promise)
], AuthController.prototype, "sendEmailVerification", null);
__decorate([
    (0, swagger_2.ApiOperation)({ summary: 'Verify Email' }),
    (0, swagger_1.ApiResponse)({ status: 200, type: core_1.MessageResponseDto }),
    (0, common_1.HttpCode)(200),
    (0, common_1.Post)('verify-email'),
    (0, core_1.SkipMfa)(),
    (0, common_1.UseGuards)(auth_guard_1.NestAuthAuthGuard),
    __param(0, (0, common_1.Body)()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [verify_email_request_dto_1.VerifyEmailRequestDto]),
    __metadata("design:returntype", Promise)
], AuthController.prototype, "verifyEmail", null);
__decorate([
    (0, swagger_2.ApiOperation)({
        summary: 'Get Client Configuration',
        description: 'Returns backend configuration for frontend clients. Includes enabled auth methods, registration settings, MFA options, tenant configuration, and SSO providers. Can be customized via clientConfig.factory in AuthModuleOptions.',
    }),
    (0, swagger_1.ApiResponse)({ status: 200, type: client_config_response_dto_1.ClientConfigResponseDto }),
    (0, common_1.HttpCode)(200),
    (0, common_1.Get)('client-config'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", Promise)
], AuthController.prototype, "getClientConfig", null);
__decorate([
    (0, swagger_2.ApiOperation)({
        summary: 'SSO Callback',
        description: 'OAuth callback endpoint for SSO providers. Exchanges authorization code for access token and returns raw SSO user info. Returns HTML page that posts SSO data to parent window and auto-closes.',
    }),
    (0, common_1.Get)('callback/:provider'),
    __param(0, (0, common_1.Param)('provider')),
    __param(1, (0, common_1.Query)()),
    __param(2, (0, common_1.Res)()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, Object, Object]),
    __metadata("design:returntype", Promise)
], AuthController.prototype, "ssoCallback", null);
exports.AuthController = AuthController = __decorate([
    (0, common_1.Controller)('auth'),
    __metadata("design:paramtypes", [auth_service_1.AuthService,
        cookie_service_1.CookieService,
        auth_config_service_1.AuthConfigService,
        client_config_service_1.ClientConfigService])
], AuthController);
//# sourceMappingURL=auth.controller.js.map