import { db } from '@/src/db/db_index'
import { productInfo, productAvailabilitySchedules } from '@/src/db/schema'
import { eq, inArray } from 'drizzle-orm';
import { initializeAllStores } from '@/src/stores/store-initializer';
import dayjs from 'dayjs';

/** 
 * Get all products that should be in stock or out of stock based on current schedules
 * Only processes products that are actually involved in availability schedules
 * Automatically updates products that need to change their availability status
 * @returns Promise<{ inStock: number[], outOfStock: number[], changed: number[] }>
 */
export async function verifyProductsAvailabilityBySchedule(reInitialize:boolean = false): Promise<{
  inStock: number[];
  outOfStock: number[];
  changed: number[];
}> {
  // Get all schedules
  const allSchedules = await db.query.productAvailabilitySchedules.findMany();

  // Extract all unique product IDs from all schedules
  const allScheduledProductIds = new Set<number>();
  for (const schedule of allSchedules) {
    for (const productId of schedule.productIds) {
      allScheduledProductIds.add(productId);
    }
  }

  // If no products are in any schedule, return empty arrays
  if (allScheduledProductIds.size === 0) {
    return { inStock: [], outOfStock: [], changed: [] };
  }

  // Get current time
  const currentTime = dayjs().format('HH:mm');

  const computedInStock: number[] = [];
  const computedOutOfStock: number[] = [];

  // Process each product that is involved in schedules
  for (const productId of allScheduledProductIds) {
    // Find applicable schedules for this product
    const applicableSchedules = allSchedules.filter(schedule => {
      return schedule.productIds.includes(productId);
    });

    // Filter active schedules (time <= current time)
    const activeSchedules = applicableSchedules.filter(schedule => 
      schedule.time <= currentTime
    );

    if (activeSchedules.length === 0) {
      // No active schedule applies - skip this product
      // (we only care about products with active schedule rules)
      continue;
    }

    // Get most recent schedule
    const mostRecentSchedule = activeSchedules.sort((a, b) => {
      if (a.time !== b.time) {
        return b.time.localeCompare(a.time);
      }
      return b.id - a.id;
    })[0];

    // Categorize based on schedule action
    if (mostRecentSchedule.action === 'in') {
      computedInStock.push(productId);
    } else {
      computedOutOfStock.push(productId);
    }
  }

  // Query products to check current availability status
  const allProductIds = [...computedInStock, ...computedOutOfStock];
  
  if (allProductIds.length === 0) {
    return { inStock: [], outOfStock: [], changed: [] };
  }

  const products = await db.query.productInfo.findMany({
    where: inArray(productInfo.id, allProductIds),
  });

  // Find products that need to change
  const toMarkInStock: number[] = [];
  const toMarkOutOfStock: number[] = [];
  const changed: number[] = [];

  for (const product of products) {
    const shouldBeInStock = computedInStock.includes(product.id);
    const currentlyOutOfStock = product.isOutOfStock;

    if (shouldBeInStock && currentlyOutOfStock) {
      // Should be in stock but currently out of stock - needs change
      toMarkInStock.push(product.id);
      changed.push(product.id);
    } else if (!shouldBeInStock && !currentlyOutOfStock) {
      // Should be out of stock but currently in stock - needs change
      toMarkOutOfStock.push(product.id);
      changed.push(product.id);
    }
  }

  // Batch update products in a single query
  if (toMarkInStock.length > 0) {
    await db.update(productInfo)
      .set({ isOutOfStock: false })
      .where(inArray(productInfo.id, toMarkInStock));
  }

  if (toMarkOutOfStock.length > 0) {
    await db.update(productInfo)
      .set({ isOutOfStock: true })
      .where(inArray(productInfo.id, toMarkOutOfStock));
  }

  // Reinitialize stores if any products changed
  if (changed.length > 0 && reInitialize) {
    console.log(`Reinitializing stores after availability changes for ${changed.length} products`);
    await initializeAllStores();
  }

  return { 
    inStock: computedInStock, 
    outOfStock: computedOutOfStock, 
    changed 
  };
}
