import { Request, Response } from "express";
import * as adminService from "../services/adminService";
import * as certificateService from "../services/certificateService";
import { sendResponse, handleError } from "../utils/apiResponse";
import {
  disable2FA,
  generate2FASetup,
  get2FAStatus,
  verifyAndEnable2FA,
} from "../services/adminService";

// @desc    Admin dashboard overview
// @route   GET /api/admin/dashboard
export const getDashboard = async (
  _req: Request,
  res: Response,
): Promise<void> => {
  try {
    const dashboard = await adminService.getDashboard();
    sendResponse(res, 200, "Dashboard fetched", dashboard);
  } catch (error) {
    handleError(res, error);
  }
};

// ─── Self ─────────────────────────────────────────────────────────────────────

// @desc    Get current logged-in admin
// @route   GET /api/admin/me
export const getMe = async (req: Request, res: Response): Promise<void> => {
  try {
    const admin = await adminService.getAdminById(req.admin!.id);
    sendResponse(res, 200, "Admin profile fetched", { admin });
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Get all admins
// @route   GET /api/admin/admins?page=1&limit=10
export const getAllAdmins = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const page = Math.max(1, parseInt(req.query.page as string) || 1);
    const limit = Math.min(
      50,
      Math.max(1, parseInt(req.query.limit as string) || 10),
    );
    const { admins, pagination } = await adminService.getAllAdmins(page, limit);
    sendResponse(
      res,
      200,
      "Admins fetched",
      { count: admins.length, admins },
      pagination,
    );
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Delete admin by ID
// @route   DELETE /api/admin/admins/:id
export const deleteAdmin = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    await adminService.deleteAdmin(req.params.id as string, req.admin!.id);
    sendResponse(res, 200, "Admin deleted successfully");
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Update current logged-in admin's profile
// @route   PUT /api/admin/me
export const updateMe = async (req: Request, res: Response): Promise<void> => {
  try {
    const { name, email } = req.body as { name?: string; email?: string };
    const admin = await adminService.updateAdmin(req.admin!.id, {
      name,
      email,
    });
    sendResponse(res, 200, "Admin profile updated", { admin });
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Upload admin avatar
// @route   PUT /api/admin/avatar
export const uploadAvatar = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    if (!req.file) {
      sendResponse(res, 400, "No image uploaded");
      return;
    }
    const admin = await adminService.uploadAdminAvatar(
      req.admin!.id,
      req.file.buffer,
      req.file.mimetype,
    );
    sendResponse(res, 200, "Avatar uploaded", { avatar: admin?.avatar, admin });
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Change own password
// @route   PUT /api/admin/change-password
export const changePassword = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const { currentPassword, newPassword } = req.body as {
      currentPassword?: string;
      newPassword?: string;
    };
    if (!currentPassword || !newPassword) {
      sendResponse(res, 400, "Please provide currentPassword and newPassword");
      return;
    }
    await adminService.changeAdminPassword(
      req.admin!.id,
      currentPassword,
      newPassword,
    );
    sendResponse(res, 200, "Password updated successfully");
  } catch (error) {
    handleError(res, error);
  }
};

// ─── User Management ──────────────────────────────────────────────────────────

// @desc    Get all users
// @route   GET /api/admin/users?page=1&limit=10
export const getAllUsers = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const page = Math.max(1, parseInt(req.query.page as string) || 1);
    const limit = Math.min(
      50,
      Math.max(1, parseInt(req.query.limit as string) || 10),
    );
    const search = (req.query.search as string) || "";

    const { users, pagination } = await adminService.getAllUsers(
      page,
      limit,
      search,
    );
    sendResponse(
      res,
      200,
      "Users fetched",
      { count: users.length, users },
      pagination,
    );
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Get all users (minimal, for dropdowns)
// @route   GET /api/admin/users/all
export const getAllUsersMinimal = async (
  _req: Request,
  res: Response,
): Promise<void> => {
  try {
    const users = await adminService.getAllUsersMinimal();
    sendResponse(res, 200, "Users fetched", { count: users.length, users });
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Get employee overview details for admin panel
// @route   GET /api/admin/employees/details/:employeeId
export const getEmployeeDetails = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const employeeId = req.params.employeeId as string | undefined;
    if (!employeeId) {
      sendResponse(res, 400, "Please provide employeeId");
      return;
    }

    const details = await adminService.getEmployeeDetails(employeeId);
    sendResponse(res, 200, "Employee details fetched successfully", details);
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Get single user by ID
// @route   GET /api/admin/users/:id
export const getUser = async (req: Request, res: Response): Promise<void> => {
  try {
    const user = await adminService.getUserById(req.params.id as string);
    sendResponse(res, 200, "User fetched", { user });
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Create a new user
// @route   POST /api/admin/users
export const createUser = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const { name, email, ...profile } = req.body as {
      name?: string;
      email?: string;
      [key: string]: unknown;
    };
    if (!name || !email) {
      sendResponse(res, 400, "Please provide name and email");
      return;
    }
    const user = await adminService.createUser(name, email, profile);
    sendResponse(
      res,
      201,
      "User created successfully. A set-password email has been sent.",
      { user },
    );
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Update user by ID
// @route   PUT /api/admin/users/:id
export const updateUser = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const user = await adminService.updateUser(
      req.params.id as string,
      req.body as Record<string, unknown>,
    );
    sendResponse(res, 200, "User updated", { user });
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Update a user's avatar (admin)
// @route   PUT /api/admin/users/:id/avatar
export const uploadUserAvatar = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    if (!req.file) {
      sendResponse(res, 400, "No image uploaded");
      return;
    }
    const user = await adminService.uploadUserAvatar(
      req.params.id as string,
      req.file.buffer,
      req.file.mimetype,
    );
    sendResponse(res, 200, "Avatar uploaded", { avatar: user?.avatar, user });
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Resend the account-setup (set password) email to an employee who hasn't set a password yet
// @route   POST /api/admin/users/:id/resend-invite
export const resendEmployeeInvite = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    await adminService.resendEmployeeInvite(req.params.id as string);
    sendResponse(res, 200, "Invitation email resent successfully");
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Change a user's password (admin)
// @route   PUT /api/admin/users/:id/change-password
export const changeUserPassword = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const { newPassword } = req.body as { newPassword?: string };
    if (!newPassword) {
      sendResponse(res, 400, "Please provide newPassword");
      return;
    }
    await adminService.changeUserPassword(req.params.id as string, newPassword);
    sendResponse(res, 200, "Password updated successfully");
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Delete user by ID
// @route   DELETE /api/admin/users/:id
export const deleteUser = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    await adminService.deleteUser(req.params.id as string);
    sendResponse(res, 200, "User deleted successfully");
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Get points leaderboard (all users sorted by points)
// @route   GET /api/admin/leaderboard
export const getLeaderboard = async (
  _req: Request,
  res: Response,
): Promise<void> => {
  try {
    const leaderboard = await adminService.getLeaderboard();
    sendResponse(res, 200, "Leaderboard fetched", {
      count: leaderboard.length,
      leaderboard,
    });
  } catch (error) {
    handleError(res, error);
  }
};

// ─── Certificate Requests ────────────────────────────────────────────────────

// @desc    Get certificate requests
// @route   GET /api/admin/certificate-requests?status=pending&page=1&limit=10
export const getCertificateRequests = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const status = req.query.status as
      | "pending"
      | "approved"
      | "rejected"
      | undefined;
    if (status && !["pending", "approved", "rejected"].includes(status)) {
      sendResponse(
        res,
        400,
        "Invalid status. Use pending, approved, or rejected",
      );
      return;
    }

    const page = Math.max(1, parseInt(req.query.page as string) || 1);
    const limit = Math.min(
      50,
      Math.max(1, parseInt(req.query.limit as string) || 10),
    );

    const { requests, pagination } =
      await certificateService.getCertificateRequestsForAdmin(
        status,
        page,
        limit,
      );
    sendResponse(
      res,
      200,
      "Certificate requests fetched",
      { requests },
      pagination,
    );
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Get certificate request by ID
// @route   GET /api/admin/certificate-requests/:id
export const getCertificateRequestById = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const request = await certificateService.getCertificateRequestByIdForAdmin(
      req.params.id as string,
    );
    sendResponse(res, 200, "Certificate request fetched", { request });
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Approve certificate request
// @route   PATCH /api/admin/certificate-requests/:id/approve
export const approveCertificateRequest = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const { admin_comment } = req.body as { admin_comment?: string };
    const result = await certificateService.approveCertificateRequest(
      req.params.id as string,
      req.admin!.id,
      admin_comment,
    );
    sendResponse(res, 200, "Certificate request approved", result);
  } catch (error) {
    handleError(res, error);
  }
};

// @desc    Reject certificate request
// @route   PATCH /api/admin/certificate-requests/:id/reject
export const rejectCertificateRequest = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const { admin_comment } = req.body as { admin_comment?: string };
    const request = await certificateService.rejectCertificateRequest(
      req.params.id as string,
      req.admin!.id,
      admin_comment,
    );
    sendResponse(res, 200, "Certificate request rejected", { request });
  } catch (error) {
    handleError(res, error);
  }
};

// ─── 2FA ──────────────────────────────────────────────────────────────────────────────────────────

export const setup2FA = async (req: Request, res: Response): Promise<void> => {
  try {
    const result = await generate2FASetup(req.admin!.id);

    sendResponse(res, 200, "2FA setup generated successfully", result);
  } catch (error) {
    handleError(res, error);
  }
};

export const verify2FA = async (req: Request, res: Response): Promise<void> => {
  try {
    const { code } = req.body;

    const result = await verifyAndEnable2FA(req.admin!.id, code);

    sendResponse(res, 200, "2FA enabled successfully", result);
  } catch (error) {
    handleError(res, error);
  }
};

export const disable2FAController = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const { code } = req.body;

    const result = await disable2FA({
      adminId: req.admin!.id,
      code,
    });

    sendResponse(res, 200, "2FA disabled successfully", result);
  } catch (error) {
    handleError(res, error);
  }
};

export const get2FAStatusController = async (
  req: Request,
  res: Response,
): Promise<void> => {
  try {
    const result = await get2FAStatus(req.admin!.id);

    sendResponse(res, 200, "2FA status fetched successfully", result);
  } catch (error) {
    handleError(res, error);
  }
};
