import { Application } from 'express';
import { Resource } from 'express-automatic-routes';
import { Req, Res } from '#interfaces/IApi';
import { SessionService, TokenService } from '#services/auth';
import { createRateLimit } from '#middlewares/auth';
import { csrfProtection } from '#middlewares/csrf';
import { sendSuccess } from '#utils/responseUtils';
import Config from '#config';

// Cache env parsing at module load time — avoids re-parsing on every request
const ACCESS_EXPIRES_IN = TokenService.parseTimeToSeconds(Config.auth.jwtExpiresIn);
const REFRESH_EXPIRES_IN = TokenService.parseTimeToSeconds(Config.auth.jwtRefreshExpiresIn);

export default (_express: Application) => {
	return <Resource>{
		post: {
			// SEC-02: Apply CSRF protection to refresh endpoint since it sets HttpOnly cookies
			// CSRF is only needed for cookie-based auth endpoints (not JWT header-based auth)
			middleware: [
				createRateLimit(15 * 60 * 1000, 30),
				csrfProtection({ enableDoubleSubmit: true, enableOriginValidation: false }),
			],
			handler: async (req: Req, res: Res) => {
				try {
					// Try to get refresh token from body first, then fallback to cookie
					const refreshToken = req.body.refresh_token || req.cookies?.refresh_token;
					const { device_info } = req.body;

					const tokens = await SessionService.refreshToken(refreshToken, device_info, req.ip, req.get('User-Agent'));

					// Set new tokens in HttpOnly cookies
					const accessCookieOptions = TokenService.getAccessTokenCookieOptions();
					const refreshCookieOptions = TokenService.getRefreshTokenCookieOptions();

					res.cookie('access_token', tokens.accessToken, accessCookieOptions);
					res.cookie('refresh_token', tokens.refreshToken, refreshCookieOptions);

					// Only include raw tokens in development mode (never based on client headers)
					// eslint-disable-next-line no-restricted-syntax
					const includeTokens = process.env.NODE_ENV === 'development';

					// Return optimized response with session info
					const responseData = {
						session: {
							expires_at: new Date(Date.now() + ACCESS_EXPIRES_IN * 1000),
							refresh_expires_at: new Date(Date.now() + REFRESH_EXPIRES_IN * 1000),
						},
						...(includeTokens
							? {
									access_token: tokens.accessToken,
									refresh_token: tokens.refreshToken,
									expires_in: ACCESS_EXPIRES_IN,
									token_type: 'Bearer',
								}
							: {}),
					};
					return sendSuccess(res, responseData);
				} catch (error) {
					return res.error(error);
				}
			},
		},
	};
};
