import { Application } from 'express';
import { Resource } from 'express-automatic-routes';
import { UserAuthProvider } from '#providers/UserAuthProvider';
import { PasswordResetTokenProvider } from '#providers/PasswordResetTokenProvider';
import { Req, Res } from '#interfaces/IApi';
import { validateZod } from '#middlewares/validators';
import { PasswordResetSubmitSchema } from '#contracts/auth/schema';
import { Errors } from '#interfaces/error';
import { PasswordService, SessionService } from '#services/auth';
import NotificationService from '#services/notification/notificationService';
import { authRateLimit } from '#middlewares/rate-limiter';
import { isPasswordRecentlyUsed, savePasswordToHistory, cleanupPasswordHistory } from '#utils/authUtils';
import { sendSuccess } from '#utils/responseUtils';
import LoggingService from '#services/file-system/logService';

const logger = new LoggingService();

export default (_express: Application) => {
	const userAuthProvider = new UserAuthProvider();
	const codeProvider = new PasswordResetTokenProvider();

	return <Resource>{
		post: {
			middleware: [authRateLimit, validateZod(PasswordResetSubmitSchema)],
			handler: async (req: Req, res: Res) => {
				const transaction = await userAuthProvider.transaction();

				try {
					const { email, new_password, code } = req.body;

					// Validate OTP (shared logic: find user, check used/expired, verify hash)
					const { user, resetCode } = await PasswordService.validatePasswordResetOtp(email, code);

					// SEC-05: Check if password was recently used before allowing change
					const recentlyUsed = await isPasswordRecentlyUsed(user.id, new_password);
					if (recentlyUsed) {
						throw Errors.validation([
							{
								field: 'new_password',
								code: 'PASSWORD_BREACHED',
								message: {
									vi: 'Mật khẩu này đã được sử dụng gần đây. Vui lòng chọn mật khẩu khác.',
									en: 'This password has been used recently. Please choose a different password.',
								},
							},
						]);
					}

					const hashedPassword = await PasswordService.hashPassword(new_password);

					const userAuths = await userAuthProvider.getAll({
						where: { user_id: user.id },
					});

					if (!userAuths.rows.length) {
						throw Errors.notFound('Thông tin xác thực');
					}

					const userAuth = userAuths.rows[0]!;

					await userAuthProvider.put(
						userAuth.id,
						{
							password_hash: hashedPassword,
							password_changed_at: new Date(),
							updated_at: new Date(),
						} as any,
						{ transaction },
					);

					// SEC-05: Save old password to history before changing
					await savePasswordToHistory(user.id, userAuth.password_hash, user.id, 'password_reset');

					// SEC-05: Cleanup old password history entries
					await cleanupPasswordHistory(user.id);

					await codeProvider.put(resetCode.id, { used_at: new Date() } as any, { transaction });

					await transaction.commit();
					// Invalidate all active sessions after password reset (security best practice)
					await SessionService.logoutAll(user.id).catch((error) => {
						logger
							.logErrorAsync('ConfirmReset', error instanceof Error ? error : new Error(String(error)), { userId: user.id })
							.catch(() => {});
					});
					// Security notification (fire-and-forget)
					NotificationService.getInstance()
						.createAndSend({
							userId: user.id,
							title: 'Mật khẩu đã được thay đổi',
							body: 'Mật khẩu của bạn vừa được đặt lại. Nếu không phải bạn, hãy liên hệ hỗ trợ.',
							type: 'security_alert',
							channel: 'in_app',
							data: { changed_at: new Date() },
						})
						.catch((error) => {
							logger
								.logErrorAsync('ConfirmReset', error instanceof Error ? error : new Error(String(error)), { userId: user.id })
								.catch(() => {});
						});

					return sendSuccess(res, null);
				} catch (error) {
					await transaction.rollback();
					return res.error(error);
				}
			},
		},
	};
};
