
import { Request, Response } from "express";
import yenv from "yenv";
import { User } from "../../../database/user/user";
import * as otpGenerator from "otp-generator"; 
import {  messages } from "../../../utills/common";
import MailService from "../../../config/MailService";
import {resetPasswordEmail} from "../../../templates/resetPasswordEmail";
import { sendErrorResponse, sendSuccessResponse } from "../../../utills/response";
const bcrypt = require("bcrypt");
const env = yenv("env.yaml", { env: "development" });
export const forgotPassword = async (req: Request, res: Response) => {
    try {
        const { email } = req.body;
        const user = await findUserByEmail(email);
        if (!user) return sendErrorResponse(res, 500, messages.userNotFound);
        const otp = otpGenerator.generate(6, { digits: true,
             specialChars: false, lowerCaseAlphabets: false, upperCaseAlphabets: false });

        const otpHash = await bcrypt.hash(otp, 10);
        const otpExpiry = new Date();
        otpExpiry.setMinutes(otpExpiry.getMinutes() + 10);

        const resetPasswordEmailContent = resetPasswordEmail(otp);

        // Update user record with hashed OTP and expiry
        await User.createQueryBuilder()
            .update()
            .set({
                otpHash,
                otpExpiry,
                otpAttempts: 0  // Reset attempts on new OTP generation
            })
            .where({ email })
            .execute();

        // Send reset password email
        const mailService = MailService.getInstance();
        await mailService.sendMail(user.id, {
            to: user.email,
            subject: "Forgot Password",
            html: resetPasswordEmailContent.html,
            from: `Change password Setup <${env.SMTP_SENDER}>`,
        });

        return sendSuccessResponse(res, 200, messages.sendOtp, "");
    } catch (err) {
        console.error("Forgot password error:", err);
        return sendErrorResponse(res, 500, messages.errorMsg);
    }
};


export const verifyOTP = async (req: Request, res: Response) => {
    try {
        const { email, otp } = req.body;
        const user = await findUserByEmail(email);
        if (!user) {
            return sendErrorResponse(res, 404, messages.userNotFound);
        }

        if (!user.otpHash) {
            return sendErrorResponse(res, 400, "No OTP has been requested");
        }

        if (!user.otpExpiry || new Date() > user.otpExpiry) {
            return sendErrorResponse(res, 400, "OTP has expired. Please request a new one");
        }

        if (user.otpAttempts >= 5) {
            await User.createQueryBuilder()
                .update()
                .set({ otpHash: undefined, otpExpiry: undefined, otpAttempts: 0 })
                .where({ email })
                .execute();
            return sendErrorResponse(res, 400, "Too many failed attempts. Please request a new OTP");
        }
        const isOtpValid = await bcrypt.compare(otp, user.otpHash);

        if (!isOtpValid) {
            await User.createQueryBuilder()
                .update()
                .set({ otpAttempts: user.otpAttempts + 1 })
                .where({ email })
                .execute();

            return sendErrorResponse(res, 400, `Invalid OTP. ${4 - user.otpAttempts} attempts remaining`);
        }
        await User.createQueryBuilder()
            .update()
            .set({ otpHash: undefined, otpExpiry: undefined, otpAttempts: 0 })
            .where({ email })
            .execute();

        return sendSuccessResponse(res, 200, messages.otpVerify, "");
    } catch (err) {
        console.error("Verify OTP error:", err);
        return sendErrorResponse(res, 500, messages.errorMsg);
    }
};

// change password
export const changePassword = async (req: Request, res: Response) => {
    try {
        const { email, password } = req.body;
        const hashedPassword = await bcrypt.hash(password, 10);
        await User.createQueryBuilder()
        .update()
        .set({ password: hashedPassword })
        .where({ email })
        .execute();

        return sendSuccessResponse(res, 200, messages.changePassword, "");
    } catch (err) {
        return sendErrorResponse(res, 500, messages.errorMsg);
    }
};

// Function to find user by email
const findUserByEmail = async (email: string) => {
    return await User.findOne({ where: { email } });
};