// File: src/services/API/RefreshTokenService.js

import ApiClient from "./ApiClient";

/**
 * RefreshTokenService - Handles token refresh API requests
 *
 * Backend API: POST /api/v1/refresh
 * Documentation: cloud/maplepress-backend/docs/API.md (lines 230-324)
 *
 * Purpose: Obtain new access and refresh tokens using an existing valid refresh token.
 * This should be called when the access token expires (after 15 minutes) to maintain
 * the user's session without requiring them to log in again.
 *
 * Token Rotation: Both tokens are regenerated on refresh. Old tokens become invalid.
 */

/**
 * Refresh the access token using a valid refresh token
 *
 * @param {string} refreshToken - Valid refresh token from login or previous refresh
 * @returns {Promise<Object>} New authentication tokens and user data
 * @throws {Error} If refresh token is invalid, expired, or session is invalid
 *
 * Response format (transformed to camelCase):
 * {
 *   userId: string,
 *   userEmail: string,
 *   userName: string,
 *   userRole: string,
 *   tenantId: string,
 *   sessionId: string,
 *   accessToken: string,
 *   accessExpiry: Date,
 *   refreshToken: string,
 *   refreshExpiry: Date,
 *   refreshedAt: Date
 * }
 */
async function refreshToken(refreshToken) {
  // Validate input
  if (!refreshToken || typeof refreshToken !== "string") {
    throw new Error("Refresh token is required");
  }

  // Prepare request body (snake_case for backend)
  const requestBody = {
    refresh_token: refreshToken.trim(),
  };

  try {
    // Make API request
    const response = await ApiClient.post("/api/v1/refresh", requestBody);

    // Transform response to camelCase for frontend
    return {
      userId: response.user_id,
      userEmail: response.user_email,
      userName: response.user_name,
      userRole: response.user_role,
      tenantId: response.tenant_id,
      sessionId: response.session_id,
      accessToken: response.access_token,
      accessExpiry: new Date(response.access_expiry),
      refreshToken: response.refresh_token,
      refreshExpiry: new Date(response.refresh_expiry),
      refreshedAt: new Date(response.refreshed_at),
    };
  } catch (error) {
    // Map backend errors to user-friendly messages
    const message = error.message?.toLowerCase() || "";

    if (message.includes("invalid") || message.includes("expired")) {
      throw new Error(
        "Your session has expired. Please log in again to continue."
      );
    }

    if (message.includes("session")) {
      throw new Error(
        "Session has expired or been invalidated. Please log in again."
      );
    }

    // Generic error
    throw new Error(
      "Unable to refresh your session. Please log in again to continue."
    );
  }
}

/**
 * Check if a refresh token is needed based on access token expiry
 *
 * @param {Date|string} accessExpiry - Access token expiry date
 * @param {number} bufferMinutes - Minutes before expiry to trigger refresh (default: 1)
 * @returns {boolean} True if token should be refreshed
 */
function shouldRefreshToken(accessExpiry, bufferMinutes = 1) {
  if (!accessExpiry) {
    return true;
  }

  const expiryDate =
    accessExpiry instanceof Date ? accessExpiry : new Date(accessExpiry);
  const now = new Date();
  const bufferMs = bufferMinutes * 60 * 1000;

  // Refresh if token expires within buffer time
  return expiryDate.getTime() - now.getTime() < bufferMs;
}

/**
 * Check if a refresh token itself is still valid
 *
 * @param {Date|string} refreshExpiry - Refresh token expiry date
 * @returns {boolean} True if refresh token is still valid
 */
function isRefreshTokenValid(refreshExpiry) {
  if (!refreshExpiry) {
    return false;
  }

  const expiryDate =
    refreshExpiry instanceof Date ? refreshExpiry : new Date(refreshExpiry);
  const now = new Date();

  return expiryDate.getTime() > now.getTime();
}

// Export service
const RefreshTokenService = {
  refreshToken,
  shouldRefreshToken,
  isRefreshTokenValid,
};

export default RefreshTokenService;
