const { logger } = require('./logger.js');
const API = require('./index.js');
const path = require('path');
const fs = require('fs');
require('./utils.js');

// Initialize key replacements
let keyReplacements = {};

try {
  const replacementsPath = path.join(
    __dirname,
    '..',
    'data',
    'replacements.json'
  );
  if (fs.existsSync(replacementsPath)) {
    const replacementsContent = fs.readFileSync(replacementsPath, 'utf8');
    keyReplacements = JSON.parse(replacementsContent);
    // logger.debug("Replacements loaded successfully");
  } else {
    logger.warn('replacements.json not found, key replacement disabled');
  }
} catch (error) {
  logger.error('Error loading replacements file:', { error: error.message });
}

// Optimized replaceJsonKeys function
const replaceJsonKeys = (obj) => {
  if (!obj || typeof obj !== 'object') return obj;

  // Fast-path for arrays
  if (Array.isArray(obj)) {
    // Only process array if it has items
    return obj.length > 0 ? obj.map(replaceJsonKeys) : obj;
  }

  const newObj = {};
  const objKeys = Object.keys(obj);

  // Fast-path for empty objects
  if (objKeys.length === 0) return obj;

  // Cache key check
  const hasKeyReplacements = Object.keys(keyReplacements).length > 0;

  for (const key of objKeys) {
    // Replace key if replacements exist
    const newKey =
      hasKeyReplacements && keyReplacements[key] ? keyReplacements[key] : key;
    let value = obj[key];

    // Replace string values if needed
    if (
      hasKeyReplacements &&
      typeof value === 'string' &&
      keyReplacements[value]
    ) {
      value = keyReplacements[value];
    }

    // Process recursively only if object/array
    newObj[newKey] =
      value && typeof value === 'object' ? replaceJsonKeys(value) : value;
  }

  return newObj;
};

// Utility regex function
const sanitizeJsonOutput = (data) => {
  if (!data) return data;

  // Convert to string to perform regex operations
  const jsonString = JSON.stringify(data);

  // Define regex pattern that matches HTML entities
  const regexPattern =
    /&lt;span class=&quot;.*?&quot;&gt;|&lt;\/span&gt;|&quot;&gt;/g;

  // Replace unwanted patterns
  const sanitizedString = jsonString.replace(regexPattern, '');

  // Parse back to object
  try {
    return JSON.parse(sanitizedString);
  } catch (e) {
    logger.error('Error parsing sanitized JSON:', e);
    return data; // Return original data if parsing fails
  }
};

// Replace the processJsonOutput function with this more efficient version
const processJsonOutput = (
  data,
  options = { sanitize: true, replaceKeys: true }
) => {
  // Use a more efficient deep clone approach instead of JSON.parse(JSON.stringify())
  function deepClone(obj) {
    if (obj === null || typeof obj !== 'object') {
      return obj;
    }

    if (Array.isArray(obj)) {
      return obj.map((item) => deepClone(item));
    }

    const clone = {};
    Object.keys(obj).forEach((key) => {
      clone[key] = deepClone(obj[key]);
    });

    return clone;
  }

  // Create a deep copy of the data to avoid reference issues
  let processedData = deepClone(data);

  // Apply sanitization if needed
  if (options.sanitize) {
    processedData = sanitizeJsonOutput(processedData);
  }

  // Apply key replacement if needed
  if (options.replaceKeys) {
    processedData = replaceJsonKeys(processedData);
  }

  return processedData;
};

// Store active sessions to avoid repeated logins
const activeSessions = new Map();

// Utility function to create a timeout promise
const timeoutPromise = (ms) => {
  return new Promise((_, reject) => {
    setTimeout(
      () => reject(new ApiTimeoutError(`Request timed out after ${ms}ms`)),
      ms
    );
  });
};

// Helper function to ensure login
const ensureLogin = async (ssoToken) => {
  if (!activeSessions.has(ssoToken)) {
    logger.info(
      `Attempting to login with SSO token: ${ssoToken.substring(0, 5)}...`
    );
    // logger.info(`Attempting to login with SSO token: ${ssoToken}`);
    const loginResult = await Promise.race([
      API.login(ssoToken),
      timeoutPromise(10000), // 10 second timeout
    ]);

    logger.debug(`Login successful: ${JSON.stringify(loginResult)}`);
    logger.debug(`Session created at: ${global.Utils.toIsoString(new Date())}`);
    activeSessions.set(ssoToken, new Date());
  } else {
    logger.debug('Using existing session');
  }
};

// Create custom error classes
class ApiTimeoutError extends Error {
  constructor(message = 'API request timed out') {
    super(message);
    this.name = 'ApiTimeoutError';
  }
}

/*
class ApiAuthError extends Error {
  constructor(message = 'Authentication failed') {
    super(message);
    this.name = 'ApiAuthError';
  }
}

class ApiDataError extends Error {
  constructor(message = 'Data processing error') {
    super(message);
    this.name = 'ApiDataError';
  }
} */

// Helper function to handle API errors
const handleApiError = (error, res) => {
  logger.error('API Error:', error);
  logger.error(`Error Stack: ${error.stack}`);
  logger.error(`Error Time: ${global.Utils.toIsoString(new Date())}`);

  // Map error types to appropriate responses
  const errorResponses = {
    ApiTimeoutError: {
      status: 200,
      body: {
        status: 'error',
        message: 'The request timed out. Please try again.',
        error_type: 'timeout',
        timestamp: global.Utils.toIsoString(new Date()),
      },
    },
    ApiAuthError: {
      status: 200,
      body: {
        status: 'error',
        message: 'Authentication failed. Please check your SSO token.',
        error_type: 'auth_failure',
        timestamp: global.Utils.toIsoString(new Date()),
      },
    },
    SyntaxError: {
      status: 200,
      body: {
        status: 'error',
        message:
          'Failed to parse API response. Refresh and try again or obtain a new SSO token.',
        error_type: 'InvalidResponseError',
        timestamp: global.Utils.toIsoString(new Date()),
      },
    },
    default: {
      status: 200,
      body: {
        status: 'error',
        message: error.message || 'An unknown error occurred',
        error_type: error.name || 'UnknownError',
        timestamp: global.Utils.toIsoString(new Date()),
      },
    },
  };

  // Get the appropriate response or use default
  const response = errorResponses[error.name] || errorResponses.default;

  return res.status(response.status).json(response.body);
};

// Helper function to remove sensitive data from headers
function sanitizeHeaders(headers) {
  const safeHeaders = { ...headers };

  // Remove potential sensitive information
  const sensitiveHeaders = ['authorization', 'cookie', 'set-cookie'];
  sensitiveHeaders.forEach((header) => {
    if (safeHeaders[header]) {
      safeHeaders[header] = '[REDACTED]';
    }
  });

  return safeHeaders;
}

module.exports = {
  activeSessions,
  timeoutPromise,
  ensureLogin,
  handleApiError,
  sanitizeHeaders,
  processJsonOutput,
};
