import { Request, Response } from "express";
import jwt from "jsonwebtoken";
import yenv from "yenv";
import { User } from "../../database/user/user";
import { RefreshToken } from "../../database/auth/refreshToken";
import { sendErrorResponse, sendSuccessResponse } from "../../utills/response";
import crypto from "crypto";
import { LessThan } from "typeorm";

const env = yenv("env.yaml", { env: "development" });

/**
 * Refresh access token using a valid refresh token
 */
export const refreshAccessToken = async (req: Request, res: Response) => {
    try {
        const { refreshToken } = req.body;

        if (!refreshToken) {
            return sendErrorResponse(res, 400, "Refresh token is required");
        }

        // Find refresh token in database
        const tokenRecord = await RefreshToken.findOne({
            where: { token: refreshToken }
        });

        if (!tokenRecord) {
            return sendErrorResponse(res, 401, "Invalid refresh token");
        }

        // Check if token is revoked
        if (tokenRecord.isRevoked) {
            return sendErrorResponse(res, 401, "Refresh token has been revoked");
        }

        // Check if token is expired
        if (new Date() > tokenRecord.expiresAt) {
            return sendErrorResponse(res, 401, "Refresh token has expired");
        }

        // Get user
        const user = await User.findOne({ where: { id: tokenRecord.userId } });
        if (!user) {
            return sendErrorResponse(res, 404, "User not found");
        }

        // Create new access token
        const tokenPayload = {
            userId: user.id,
            email: user.email,
            role: user.isAdmin ? 'admin' : 'user'
        };
        const newAccessToken = jwt.sign(tokenPayload, env.JWT_SECRET, { expiresIn: "15m" });

        // Optionally rotate refresh token (create new one and revoke old one)
        const newRefreshTokenString = crypto.randomBytes(64).toString('hex');
        const refreshTokenExpiry = new Date();
        refreshTokenExpiry.setDate(refreshTokenExpiry.getDate() + 7);

        const newRefreshToken = RefreshToken.create({
            token: newRefreshTokenString,
            userId: user.id,
            expiresAt: refreshTokenExpiry,
            createdByIp: req.ip ?? req.connection.remoteAddress,
        });
        await newRefreshToken.save();

        // Revoke old refresh token
        tokenRecord.isRevoked = true;
        await tokenRecord.save();

        return sendSuccessResponse(res, 200, "Token refreshed successfully", {
            token: newAccessToken,
            refreshToken: newRefreshTokenString,
        });
    } catch (err) {
        console.error("Token refresh error:", err);
        return sendErrorResponse(res, 500, "Error refreshing token");
    }
};

/**
 * Clean up expired refresh tokens (should be called periodically via cron)
 */
export const cleanupExpiredTokens = async () => {
    try {
        await RefreshToken.delete({
            expiresAt: LessThan(new Date())
        });
        console.log("Expired refresh tokens cleaned up");
    } catch (err) {
        console.error("Error cleaning up expired tokens:", err);
    }
};
