const dotenv = require("dotenv");
const path = require("path");
const { outputProgress, formatElapsedTime } = require('./metrics-new/utils/progress');
const { setupConnections, closeConnections } = require('./import/utils');
const importCategories = require('./import/categories');
const { importProducts } = require('./import/products');
const importOrders = require('./import/orders');
const importPurchaseOrders = require('./import/purchase-orders');
const importDailyDeals = require('./import/daily-deals');
const importStockSnapshots = require('./import/stock-snapshots');

dotenv.config({ path: path.join(__dirname, "../.env") });

// Constants to control which imports run
const IMPORT_CATEGORIES = true;
const IMPORT_PRODUCTS = true;
const IMPORT_ORDERS = true;
const IMPORT_PURCHASE_ORDERS = true;
const IMPORT_DAILY_DEALS = true;
const IMPORT_STOCK_SNAPSHOTS = true;

// Add flag for incremental updates
const INCREMENTAL_UPDATE = process.env.INCREMENTAL_UPDATE !== 'false';  // Default to true unless explicitly set to false

// SSH configuration
// Current UTC offset of America/Chicago ('-05:00' or '-06:00'), DST-aware.
function currentChicagoOffset() {
  const tzName = new Intl.DateTimeFormat('en-US', {
    timeZone: 'America/Chicago',
    timeZoneName: 'longOffset',
  })
    .formatToParts(new Date())
    .find((p) => p.type === 'timeZoneName').value; // e.g. 'GMT-05:00'
  return tzName.replace('GMT', '') || '+00:00';
}

const sshConfig = {
  ssh: {
    host: process.env.PROD_SSH_HOST,
    port: process.env.PROD_SSH_PORT || 22,
    username: process.env.PROD_SSH_USER,
    privateKey: process.env.PROD_SSH_KEY_PATH
      ? require("fs").readFileSync(process.env.PROD_SSH_KEY_PATH)
      : undefined,
    compress: true, // Enable SSH compression
  },
  prodDbConfig: {
    // MySQL config for production
    host: process.env.PROD_DB_HOST || "localhost",
    user: process.env.PROD_DB_USER,
    password: process.env.PROD_DB_PASSWORD,
    database: process.env.PROD_DB_NAME,
    port: process.env.PROD_DB_PORT || 3306,
    // DATETIMEs on this server store Central wall-clock. Use the CURRENT
    // Chicago offset (DST-aware) so both inbound parsing and outbound
    // serialization are correct in winter (CST=-06:00) and summer
    // (CDT=-05:00). adjustDateForMySQL() in utils.js remains as a runtime
    // safety net (its correction is 0 when this offset matches the server).
    timezone: currentChicagoOffset(),
  },
  localDbConfig: {
    // PostgreSQL config for local
    host: process.env.DB_HOST,
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    database: process.env.DB_NAME,
    port: process.env.DB_PORT || 5432,
    ssl: process.env.DB_SSL === 'true',
    connectionTimeoutMillis: 60000,
    idleTimeoutMillis: 30000,
    max: 10 // connection pool max size
  }
};

let isImportCancelled = false;

// Add cancel function
function cancelImport() {
    isImportCancelled = true;
    outputProgress({
        status: 'cancelled',
        operation: 'Import process',
        message: 'Import cancelled by user',
        current: 0,
        total: 0,
        elapsed: null,
        remaining: null,
        rate: 0
    });
}

async function main() {
  const startTime = Date.now();
  let connections;
  let completedSteps = 0;
  let importHistoryId;
  const totalSteps = [
    IMPORT_CATEGORIES,
    IMPORT_PRODUCTS,
    IMPORT_ORDERS,
    IMPORT_PURCHASE_ORDERS,
    IMPORT_DAILY_DEALS,
    IMPORT_STOCK_SNAPSHOTS
  ].filter(Boolean).length;

  try {
    // Initial progress update
    outputProgress({
      status: "running",
      operation: "Import process",
      message: `Initializing SSH tunnel for ${INCREMENTAL_UPDATE ? 'incremental' : 'full'} import...`,
      current: completedSteps,
      total: totalSteps,
      elapsed: formatElapsedTime(startTime)
    });

    connections = await setupConnections(sshConfig);
    const { prodConnection, localConnection } = connections;

    if (isImportCancelled) throw new Error("Import cancelled");

    // Clean up any previously running imports that weren't completed
    await localConnection.query(`
      UPDATE import_history 
      SET 
        status = 'cancelled',
        end_time = NOW(),
        duration_seconds = EXTRACT(EPOCH FROM (NOW() - start_time))::INTEGER,
        error_message = 'Previous import was not completed properly'
      WHERE status = 'running'
    `);

    // Create import history record for the overall session
    try {
      const [historyResult] = await localConnection.query(`
        INSERT INTO import_history (
          table_name, 
          start_time, 
          is_incremental,
          status,
          additional_info
        ) VALUES (
          'all_tables',
          NOW(),
          $1::boolean,
          'running',
          jsonb_build_object(
            'categories_enabled', $2::boolean,
            'products_enabled', $3::boolean,
            'orders_enabled', $4::boolean,
            'purchase_orders_enabled', $5::boolean,
            'daily_deals_enabled', $6::boolean,
            'stock_snapshots_enabled', $7::boolean
          )
        ) RETURNING id
      `, [INCREMENTAL_UPDATE, IMPORT_CATEGORIES, IMPORT_PRODUCTS, IMPORT_ORDERS, IMPORT_PURCHASE_ORDERS, IMPORT_DAILY_DEALS, IMPORT_STOCK_SNAPSHOTS]);
      importHistoryId = historyResult.rows[0].id;
    } catch (error) {
      console.error("Error creating import history record:", error);
      outputProgress({
        status: "error",
        operation: "Import process",
        message: "Failed to create import history record",
        error: error.message
      });
      throw error;
    }

    const results = {
      categories: null,
      products: null,
      orders: null,
      purchaseOrders: null,
      dailyDeals: null,
      stockSnapshots: null
    };

    let totalRecordsAdded = 0;
    let totalRecordsUpdated = 0;
    let totalRecordsDeleted = 0;  // Add tracking for deleted records
    let totalRecordsSkipped = 0;  // Track skipped/filtered records
    const stepTimings = {};

    // Run each import based on constants
    if (IMPORT_CATEGORIES) {
      const stepStart = Date.now();
      results.categories = await importCategories(prodConnection, localConnection);
      stepTimings.categories = Math.round((Date.now() - stepStart) / 1000);
      
      if (isImportCancelled) throw new Error("Import cancelled");
      completedSteps++;
      console.log('Categories import result:', results.categories);
      totalRecordsAdded += parseInt(results.categories?.recordsAdded || 0);
      totalRecordsUpdated += parseInt(results.categories?.recordsUpdated || 0);
    }

    if (IMPORT_PRODUCTS) {
      const stepStart = Date.now();
      results.products = await importProducts(prodConnection, localConnection, INCREMENTAL_UPDATE);
      stepTimings.products = Math.round((Date.now() - stepStart) / 1000);
      
      if (isImportCancelled) throw new Error("Import cancelled");
      completedSteps++;
      console.log('Products import result:', results.products);
      totalRecordsAdded += parseInt(results.products?.recordsAdded || 0);
      totalRecordsUpdated += parseInt(results.products?.recordsUpdated || 0);
      totalRecordsSkipped += parseInt(results.products?.skippedUnchanged || 0);
    }

    if (IMPORT_ORDERS) {
      const stepStart = Date.now();
      results.orders = await importOrders(prodConnection, localConnection, INCREMENTAL_UPDATE);
      stepTimings.orders = Math.round((Date.now() - stepStart) / 1000);
      
      if (isImportCancelled) throw new Error("Import cancelled");
      completedSteps++;
      console.log('Orders import result:', results.orders);
      totalRecordsAdded += parseInt(results.orders?.recordsAdded || 0);
      totalRecordsUpdated += parseInt(results.orders?.recordsUpdated || 0);
      totalRecordsSkipped += parseInt(results.orders?.totalSkipped || 0);
    }

    if (IMPORT_PURCHASE_ORDERS) {
      try {
        const stepStart = Date.now();
        results.purchaseOrders = await importPurchaseOrders(prodConnection, localConnection, INCREMENTAL_UPDATE);
        stepTimings.purchaseOrders = Math.round((Date.now() - stepStart) / 1000);
        
        if (isImportCancelled) throw new Error("Import cancelled");
        completedSteps++;
        console.log('Purchase orders import result:', results.purchaseOrders);
        
        // Handle potential error status
        if (results.purchaseOrders?.status === 'error') {
          console.error('Purchase orders import had an error:', results.purchaseOrders.error);
        } else {
          totalRecordsAdded += parseInt(results.purchaseOrders?.recordsAdded || 0);
          totalRecordsUpdated += parseInt(results.purchaseOrders?.recordsUpdated || 0);
          totalRecordsDeleted += parseInt(results.purchaseOrders?.recordsDeleted || 0);
        }
      } catch (error) {
        console.error('Error during purchase orders import:', error);
        // Continue with other imports, don't fail the whole process
        results.purchaseOrders = {
          status: 'error',
          error: error.message,
          recordsAdded: 0,
          recordsUpdated: 0
        };
      }
    }

    if (IMPORT_DAILY_DEALS) {
      try {
        const stepStart = Date.now();
        results.dailyDeals = await importDailyDeals(prodConnection, localConnection);
        stepTimings.dailyDeals = Math.round((Date.now() - stepStart) / 1000);

        if (isImportCancelled) throw new Error("Import cancelled");
        completedSteps++;
        console.log('Daily deals import result:', results.dailyDeals);

        if (results.dailyDeals?.status === 'error') {
          console.error('Daily deals import had an error:', results.dailyDeals.error);
        } else {
          totalRecordsAdded += parseInt(results.dailyDeals?.recordsAdded || 0);
          totalRecordsUpdated += parseInt(results.dailyDeals?.recordsUpdated || 0);
          totalRecordsDeleted += parseInt(results.dailyDeals?.recordsDeleted || 0);
        }
      } catch (error) {
        console.error('Error during daily deals import:', error);
        results.dailyDeals = {
          status: 'error',
          error: error.message,
          recordsAdded: 0,
          recordsUpdated: 0
        };
      }
    }

    if (IMPORT_STOCK_SNAPSHOTS) {
      try {
        const stepStart = Date.now();
        results.stockSnapshots = await importStockSnapshots(prodConnection, localConnection, INCREMENTAL_UPDATE);
        stepTimings.stockSnapshots = Math.round((Date.now() - stepStart) / 1000);

        if (isImportCancelled) throw new Error("Import cancelled");
        completedSteps++;
        console.log('Stock snapshots import result:', results.stockSnapshots);

        if (results.stockSnapshots?.status === 'error') {
          console.error('Stock snapshots import had an error:', results.stockSnapshots.error);
        } else {
          totalRecordsAdded += parseInt(results.stockSnapshots?.recordsAdded || 0);
          totalRecordsUpdated += parseInt(results.stockSnapshots?.recordsUpdated || 0);
        }
      } catch (error) {
        console.error('Error during stock snapshots import:', error);
        results.stockSnapshots = {
          status: 'error',
          error: error.message,
          recordsAdded: 0,
          recordsUpdated: 0
        };
      }
    }

    const endTime = Date.now();
    const totalElapsedSeconds = Math.round((endTime - startTime) / 1000);

    // Update import history with final stats
    await localConnection.query(`
      UPDATE import_history 
      SET 
        end_time = NOW(),
        duration_seconds = $1,
        records_added = $2,
        records_updated = $3,
        status = 'completed',
        additional_info = jsonb_build_object(
          'categories_enabled', $4::boolean,
          'products_enabled', $5::boolean,
          'orders_enabled', $6::boolean,
          'purchase_orders_enabled', $7::boolean,
          'daily_deals_enabled', $8::boolean,
          'categories_result', COALESCE($9::jsonb, 'null'::jsonb),
          'products_result', COALESCE($10::jsonb, 'null'::jsonb),
          'orders_result', COALESCE($11::jsonb, 'null'::jsonb),
          'purchase_orders_result', COALESCE($12::jsonb, 'null'::jsonb),
          'daily_deals_result', COALESCE($13::jsonb, 'null'::jsonb),
          'stock_snapshots_enabled', $14::boolean,
          'stock_snapshots_result', COALESCE($15::jsonb, 'null'::jsonb),
          'total_deleted', $16::integer,
          'total_skipped', $17::integer,
          'step_timings', $18::jsonb
        )
      WHERE id = $19
    `, [
      totalElapsedSeconds,
      parseInt(totalRecordsAdded),
      parseInt(totalRecordsUpdated),
      IMPORT_CATEGORIES,
      IMPORT_PRODUCTS,
      IMPORT_ORDERS,
      IMPORT_PURCHASE_ORDERS,
      IMPORT_DAILY_DEALS,
      JSON.stringify(results.categories),
      JSON.stringify(results.products),
      JSON.stringify(results.orders),
      JSON.stringify(results.purchaseOrders),
      JSON.stringify(results.dailyDeals),
      IMPORT_STOCK_SNAPSHOTS,
      JSON.stringify(results.stockSnapshots),
      totalRecordsDeleted,
      totalRecordsSkipped,
      JSON.stringify(stepTimings),
      importHistoryId
    ]);

    outputProgress({
      status: "complete",
      operation: "Import process",
      message: `${INCREMENTAL_UPDATE ? 'Incremental' : 'Full'} import completed successfully in ${formatElapsedTime(totalElapsedSeconds)}`,
      current: completedSteps,
      total: totalSteps,
      elapsed: formatElapsedTime(startTime),
      timing: {
        start_time: new Date(startTime).toISOString(),
        end_time: new Date(endTime).toISOString(),
        elapsed_time: formatElapsedTime(startTime),
        elapsed_seconds: totalElapsedSeconds,
        total_duration: formatElapsedTime(totalElapsedSeconds)
      },
      results
    });

    return results;
  } catch (error) {
    const endTime = Date.now();
    const totalElapsedSeconds = Math.round((endTime - startTime) / 1000);

    // Update import history with error
    if (importHistoryId && connections?.localConnection) {
      await connections.localConnection.query(`
        UPDATE import_history 
        SET 
          end_time = NOW(),
          duration_seconds = $1,
          status = $2,
          error_message = $3
        WHERE id = $4
      `, [totalElapsedSeconds, error.message === "Import cancelled" ? 'cancelled' : 'failed', error.message, importHistoryId]);
    }

    console.error("Error during import process:", error);
    outputProgress({
      status: error.message === "Import cancelled" ? "cancelled" : "error",
      operation: "Import process",
      message: error.message === "Import cancelled" 
        ? `${INCREMENTAL_UPDATE ? 'Incremental' : 'Full'} import cancelled by user after ${formatElapsedTime(totalElapsedSeconds)}`
        : `${INCREMENTAL_UPDATE ? 'Incremental' : 'Full'} import failed after ${formatElapsedTime(totalElapsedSeconds)}`,
      error: error.message,
      current: completedSteps,
      total: totalSteps,
      elapsed: formatElapsedTime(startTime),
      timing: {
        start_time: new Date(startTime).toISOString(),
        end_time: new Date(endTime).toISOString(),
        elapsed_time: formatElapsedTime(startTime),
        elapsed_seconds: totalElapsedSeconds,
        total_duration: formatElapsedTime(totalElapsedSeconds)
      }
    });
    throw error;
  } finally {
    if (connections) {
      await closeConnections(connections).catch(err => {
        console.error("Error closing connections:", err);
      });
    }
  }
}

// Run the import only if this is the main module
if (require.main === module) {
  main().then((results) => {
    console.log('Import completed successfully:', results);
    // Force exit after a small delay to ensure all logs are written
    setTimeout(() => process.exit(0), 500);
  }).catch((error) => {
    console.error("Unhandled error in main process:", error);
    // Force exit with error code after a small delay
    setTimeout(() => process.exit(1), 500);
  });
}

// Export the functions needed by the route
module.exports = {
  main,
  cancelImport,
};
