// **WORKER-COMPATIBLE ENVIRONMENT SETUP**: Must be at the very top
// This prevents "window is not defined" errors when sql.js tries to access window.crypto
if (typeof window === "undefined") {
  // We're in a worker context - provide minimal polyfills
  globalThis.window = globalThis;

  // Enhanced crypto polyfill
  if (typeof crypto === "undefined") {
    globalThis.crypto = {
      getRandomValues: (array) => {
        // Simple fallback for worker context
        for (let i = 0; i < array.length; i++) {
          array[i] = Math.floor(Math.random() * 256);
        }
        return array;
      },
      subtle: {
        generateKey: async () => ({ type: "secret" }),
        sign: async () => new Uint8Array(32),
        verify: async () => true,
        digest: async () => new Uint8Array(32),
      },
    };
  } else if (!crypto.getRandomValues) {
    // Crypto exists but doesn't have getRandomValues - extend it
    crypto.getRandomValues = (array) => {
      // Simple fallback for worker context
      for (let i = 0; i < array.length; i++) {
        array[i] = Math.floor(Math.random() * 256);
      }
      return array;
    };
  }
}

/**
 * SQL Worker Thread Handler for TimeSafari Web Platform
 *
 * This worker handles all database operations for the web platform,
 * ensuring single-threaded database access and preventing double migrations.
 *
 * Architecture:
 * - Main thread sends messages to this worker
 * - Worker initializes database once and handles all SQL operations
 * - Results are sent back to main thread via postMessage
 *
 * @author Matthew Raymer
 * @version 1.0.0
 * @since 2025-07-02
 */

import { logger } from "./utils/logger";

/**
 * Worker state management
 */
let isInitialized = false;
let initializationPromise = null;
let databaseService = null;

/**
 * Lazy load database service to prevent circular dependencies
 */
async function getDatabaseService() {
  if (!databaseService) {
    // Dynamic import to prevent circular dependency
    const { default: AbsurdSqlDatabaseService } = await import(
      "./services/AbsurdSqlDatabaseService"
    );
    // Get the singleton instance (only created when needed)
    databaseService = AbsurdSqlDatabaseService.getInstance();
  }
  return databaseService;
}

/**
 * Send response back to main thread
 */
function sendResponse(id, type, data = null, error = null) {
  const response = {
    id,
    type,
    ...(data && { data }),
    ...(error && { error }),
  };
  postMessage(response);
}

/**
 * Initialize database service
 */
async function initializeDatabase() {
  if (isInitialized) {
    return;
  }

  if (initializationPromise) {
    return initializationPromise;
  }

  initializationPromise = (async () => {
    try {
      const dbService = await getDatabaseService();
      await dbService.initialize();
      isInitialized = true;
    } catch (error) {
      logger.error("[SQLWorker] Database initialization failed:", error);
      isInitialized = false;
      initializationPromise = null;
      throw error;
    }
  })();

  return initializationPromise;
}

/**
 * Handle database query operations
 */
async function handleQuery(id, sql, params = []) {
  try {
    await initializeDatabase();

    const dbService = await getDatabaseService();
    const result = await dbService.query(sql, params);

    sendResponse(id, "success", { result });
  } catch (error) {
    logger.error(`[SQLWorker] Query failed:`, error);
    sendResponse(id, "error", null, {
      message: error.message,
      stack: error.stack,
    });
  }
}

/**
 * Handle database execution operations (INSERT, UPDATE, DELETE)
 */
async function handleExec(id, sql, params = []) {
  try {
    await initializeDatabase();

    const dbService = await getDatabaseService();
    const result = await dbService.run(sql, params);

    sendResponse(id, "success", result);
  } catch (error) {
    logger.error(`[SQLWorker] Statement execution failed:`, error);
    sendResponse(id, "error", null, {
      message: error.message,
      stack: error.stack,
    });
  }
}

/**
 * Handle database get one row operations
 */
async function handleGetOneRow(id, sql, params = []) {
  try {
    await initializeDatabase();

    const dbService = await getDatabaseService();
    const result = await dbService.query(sql, params);
    const oneRow = result?.[0]?.values?.[0];

    sendResponse(id, "success", oneRow);
  } catch (error) {
    logger.error(`[SQLWorker] GetOneRow failed:`, error);
    sendResponse(id, "error", null, {
      message: error.message,
      stack: error.stack,
    });
  }
}

/**
 * Handle initialization request
 */
async function handleInit(id) {
  try {
    await initializeDatabase();
    sendResponse(id, "init-complete");
  } catch (error) {
    logger.error("[SQLWorker] Initialization request failed:", error);
    sendResponse(id, "error", null, {
      message: error.message,
      stack: error.stack,
    });
  }
}

/**
 * Handle ping request for health check
 */
function handlePing(id) {
  sendResponse(id, "pong");
}

/**
 * Main message handler
 */
onmessage = function (event) {
  const { id, type, sql, params } = event.data;

  if (!id || !type) {
    logger.error("[SQLWorker] Invalid message received:", event.data);
    return;
  }

  switch (type) {
    case "query":
      handleQuery(id, sql, params);
      break;

    case "exec":
      handleExec(id, sql, params);
      break;

    case "getOneRow":
      handleGetOneRow(id, sql, params);
      break;

    case "init":
      handleInit(id);
      break;

    case "ping":
      handlePing(id);
      break;

    default:
      logger.error(`[SQLWorker] Unknown message type: ${type}`);
      sendResponse(id, "error", null, {
        message: `Unknown message type: ${type}`,
      });
      break;
  }
};

/**
 * Handle worker errors
 */
onerror = function (error) {
  logger.error("[SQLWorker] Worker error:", error);
};

/**
 * Auto-initialize on worker startup (removed to prevent circular dependency)
 * Initialization now happens on first database operation
 */
// Use console for critical startup message to avoid circular dependency
// eslint-disable-next-line no-console
console.log("[SQLWorker] Worker loaded, ready to receive messages");
