/**
 * Shared test utilities for DashCaddy test suite
 */
const express = require('express');

/**
 * Create a mock credential manager
 */
function createMockCredentialManager() {
  return {
    store: jest.fn().mockResolvedValue(true),
    retrieve: jest.fn().mockResolvedValue(null),
    delete: jest.fn().mockResolvedValue(true),
    list: jest.fn().mockResolvedValue([]),
    getMetadata: jest.fn().mockResolvedValue(null),
    rotateEncryptionKey: jest.fn().mockResolvedValue(true),
    exportBackup: jest.fn().mockResolvedValue('encrypted-backup'),
    importBackup: jest.fn().mockResolvedValue(true),
  };
}

/**
 * Create a mock crypto utils module
 */
function createMockCryptoUtils() {
  const fixedKey = Buffer.alloc(32, 'a');
  return {
    encrypt: jest.fn(data => `mock-iv:mock-tag:${Buffer.from(String(data)).toString('base64')}`),
    decrypt: jest.fn(data => {
      const parts = data.split(':');
      return Buffer.from(parts[2], 'base64').toString('utf8');
    }),
    isEncrypted: jest.fn(data => typeof data === 'string' && data.split(':').length === 3),
    encryptFields: jest.fn((obj, fields) => ({ ...obj, _encrypted: true, _encryptedFields: fields })),
    decryptFields: jest.fn(obj => {
      const result = { ...obj };
      delete result._encrypted;
      delete result._encryptedFields;
      return result;
    }),
    loadOrCreateKey: jest.fn(() => fixedKey),
    clearCachedKey: jest.fn(),
    rotateKey: jest.fn(() => ({ oldKey: fixedKey, newKey: Buffer.alloc(32, 'b') })),
    deriveKey: jest.fn().mockResolvedValue(fixedKey),
    decryptWithKey: jest.fn(data => {
      const parts = data.split(':');
      return Buffer.from(parts[2], 'base64').toString('utf8');
    }),
    readEncryptedFile: jest.fn().mockReturnValue(null),
    writeEncryptedFile: jest.fn(),
    migrateToEncrypted: jest.fn(obj => obj),
  };
}

/**
 * Create a mock state manager
 */
function createMockStateManager() {
  let data = [];
  return {
    read: jest.fn().mockResolvedValue(data),
    write: jest.fn().mockResolvedValue(),
    update: jest.fn(async fn => { data = fn(data); return data; }),
    addItem: jest.fn().mockResolvedValue(),
    removeItem: jest.fn().mockResolvedValue(),
    updateItem: jest.fn().mockResolvedValue(),
    findItem: jest.fn().mockResolvedValue(null),
    _setData: (newData) => { data = newData; },
  };
}

/**
 * Create a mock logger
 */
function createMockLogger() {
  return {
    info: jest.fn(),
    warn: jest.fn(),
    error: jest.fn(),
    debug: jest.fn(),
  };
}

/**
 * Build a minimal Express app for route testing with supertest
 */
function buildTestApp(routeFactory, deps, prefix = '/api') {
  const app = express();
  app.use(express.json());
  const router = routeFactory(deps);
  app.use(prefix, router);
  // Error handler
  const { errorMiddleware } = require('../../../src/utilities/error-handler');
  app.use(errorMiddleware);
  return app;
}

/**
 * Create mock Express req/res/next for middleware testing
 */
function createMockReqRes(overrides = {}) {
  const req = {
    method: 'GET',
    path: '/test',
    headers: {},
    cookies: {},
    ip: '127.0.0.1',
    protocol: 'https',
    secure: true,
    body: {},
    params: {},
    query: {},
    get: jest.fn(header => req.headers[header.toLowerCase()]),
    ...overrides,
  };

  const res = {
    status: jest.fn().mockReturnThis(),
    json: jest.fn().mockReturnThis(),
    send: jest.fn().mockReturnThis(),
    set: jest.fn().mockReturnThis(),
    cookie: jest.fn().mockReturnThis(),
    setHeader: jest.fn().mockReturnThis(),
    getHeader: jest.fn(),
    end: jest.fn(),
  };

  const next = jest.fn();

  return { req, res, next };
}

module.exports = {
  createMockCredentialManager,
  createMockCryptoUtils,
  createMockStateManager,
  createMockLogger,
  buildTestApp,
  createMockReqRes,
};
