import { Request, Response } from "express";
import * as authService from "../services/authService";
import { sendResponse, handleError } from "../utils/apiResponse";

const isProd = process.env.NODE_ENV === "production";
const COOKIE_OPTIONS = {
  httpOnly: true,
  secure: isProd,
  sameSite: (isProd ? "none" : "lax") as "none" | "lax",
  maxAge: 7 * 24 * 60 * 60 * 1000,
};

// @desc    Register Admin
// @route   POST /api/auth/admin/register
export const adminregister = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const { name, email, password } = req.body;
    if (!name || !email || !password) {
      sendResponse(res, 400, "Please provide name, email and password");
      return;
    }
    if (typeof name !== 'string' || name.trim().length < 2 || name.trim().length > 20) {
      sendResponse(res, 400, "Name must be 2-20 characters");
      return;
    }
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(email)) {
      sendResponse(res, 400, "Invalid email format");
      return;
    }
    const admin = await authService.registerAdmin(name, email, password);
    sendResponse(res, 201, "Admin registered successfully", { admin });
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Login Admin
// @route   POST /api/auth/admin/login
export const adminlogin = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const { email, password } = req.body;
    if (!email || !password) {
      sendResponse(res, 400, "Please provide email and password");
      return;
    }
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(email)) {
      sendResponse(res, 400, "Invalid email format");
      return;
    }
    const result = await authService.loginAdmin(
      email,
      password,
      req.ip,
    );

    if ("requires_2fa" in result && result.requires_2fa) {
      sendResponse(res, 200, "OTP verification required", result);
      return;
    }

    res.cookie("adminRefreshToken", result.refreshToken, COOKIE_OPTIONS);
    sendResponse(res, 200, "Login successful", {
      accessToken: result.accessToken,
      admin: result.admin,
    });
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Verify admin OTP challenge and complete login
// @route   POST /api/auth/verify-otp
export const verifyOtpController = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const { challenge_token, code } = req.body as {
      challenge_token?: string;
      code?: string;
    };

    if (!challenge_token || !code) {
      sendResponse(res, 400, "Please provide challenge_token and code");
      return;
    }

    if (!/^\d{6}$/.test(code)) {
      sendResponse(res, 400, "Code must be a 6 digit OTP");
      return;
    }

    const result = await authService.verifyOtpLogin(challenge_token, code);
    res.cookie("adminRefreshToken", result.refreshToken, COOKIE_OPTIONS);
    sendResponse(res, 200, "Login successful", {
      token: result.accessToken,
      user: result.admin,
    });
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Refresh Admin access token
// @route   POST /api/auth/admin/refresh
export const adminRefresh = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const refreshToken = req.cookies?.adminRefreshToken as string;
    const { accessToken, refreshToken: newRefreshToken } =
      await authService.refreshAdminToken(refreshToken);
    res.cookie("adminRefreshToken", newRefreshToken, COOKIE_OPTIONS);
    sendResponse(res, 200, "Token refreshed", { accessToken });
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Logout Admin
// @route   POST /api/auth/admin/logout
export const adminLogout = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const refreshToken = req.cookies?.adminRefreshToken as string;
    await authService.logoutAdmin(refreshToken);
    res.clearCookie("adminRefreshToken", COOKIE_OPTIONS);
    sendResponse(res, 200, "Logged out successfully");
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Register User
// @route   POST /api/auth/user/register
export const userregister = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const { name, email, password } = req.body;
    if (!name || !email || !password) {
      sendResponse(res, 400, "Please provide name, email and password");
      return;
    }
    if (typeof name !== 'string' || name.trim().length < 2 || name.trim().length > 20) {
      sendResponse(res, 400, "Name must be 2-20 characters");
      return;
    }
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(email)) {
      sendResponse(res, 400, "Invalid email format");
      return;
    }
    const user = await authService.registerUser(name, email, password);
    sendResponse(res, 201, "User registered successfully", { user });
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Login User
// @route   POST /api/auth/user/login
export const userlogin = async (req: Request, res: Response): Promise<void> => {
  try {
    const { email, password } = req.body;
    if (!email || !password) {
      sendResponse(res, 400, "Please provide email and password");
      return;
    }
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(email)) {
      sendResponse(res, 400, "Invalid email format");
      return;
    }
    const { accessToken, refreshToken, user } = await authService.loginUser(
      email,
      password,
      req.ip,
    );
    res.cookie("userRefreshToken", refreshToken, COOKIE_OPTIONS);

    // Send push notification on login (fire and forget)
    import('../services/pushNotification.service').then(({ sendPushNotification }) => {
      sendPushNotification(
        user.id.toString(),
        'Login Successful',
        'You have logged in successfully.',
        'GENERAL',
        { event: 'login' }
      ).catch(() => {});
    });

    sendResponse(res, 200, "Login successful", { accessToken, user });
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Refresh User access token
// @route   POST /api/auth/user/refresh
export const userRefresh = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const refreshToken = req.cookies?.userRefreshToken as string;
    const { accessToken, refreshToken: newRefreshToken } =
      await authService.refreshUserToken(refreshToken);
    res.cookie("userRefreshToken", newRefreshToken, COOKIE_OPTIONS);
    sendResponse(res, 200, "Token refreshed", { accessToken });
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Logout User
// @route   POST /api/auth/user/logout
export const userLogout = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const refreshToken = req.cookies?.userRefreshToken as string;
    await authService.logoutUser(refreshToken);
    res.clearCookie("userRefreshToken", COOKIE_OPTIONS);
    sendResponse(res, 200, "Logged out successfully");
  } catch (error) {
    handleError(res, error);
  }
};

// ─── Forgot / Reset Password ──────────────────────────────────────────────────

// @desc    Admin forgot password — send reset email
// @route   POST /api/auth/admin/forgot-password
export const adminForgotPassword = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const { email } = req.body as { email?: string };
    if (!email) {
      sendResponse(res, 400, "Please provide email");
      return;
    }
    await authService.forgotPasswordAdmin(email);
    sendResponse(res, 200, "If that email is registered, a reset link has been sent.");
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Admin reset password using token
// @route   POST /api/auth/admin/reset-password
export const adminResetPassword = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const { token, newPassword } = req.body as {
      token?: string;
      newPassword?: string;
    };
    if (!token || !newPassword) {
      sendResponse(res, 400, "Please provide token and newPassword");
      return;
    }
    await authService.resetPasswordAdmin(token, newPassword);
    sendResponse(res, 200, "Password reset successfully");
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    User forgot password — send reset email
// @route   POST /api/auth/user/forgot-password
export const userForgotPassword = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    let { email } = req.body as { email?: string };
    if (!email || typeof email !== 'string' || !email.trim()) {
      sendResponse(res, 400, "Please provide a valid email");
      return;
    }
    email = email.trim();
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(email)) {
      sendResponse(res, 400, "Invalid email format");
      return;
    }
    await authService.forgotPasswordUser(email);
    sendResponse(res, 200, "If that email is registered, a reset link has been sent.");
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    User reset password using token
// @route   POST /api/auth/user/reset-password
export const userResetPassword = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const { token, newPassword } = req.body as {
      token?: string;
      newPassword?: string;
    };
    if (!token || !newPassword) {
      sendResponse(res, 400, "Please provide token and newPassword");
      return;
    }
    await authService.resetPasswordUser(token, newPassword);
    sendResponse(res, 200, "Password reset successfully");
  } catch (error) {
    handleError(res, error);
  }
};
