import { router, publicProcedure } from '../trpc-index';
import { db } from '../../db/db_index';
import { productInfo, units, productSlots, deliverySlotInfo, storeInfo, productTags, productTagInfo } from '../../db/schema';
import { eq, gt, and, sql, inArray } from 'drizzle-orm';
import { generateSignedUrlsFromS3Urls, generateSignedUrlFromS3Url } from '../../lib/s3-client';
import { z } from 'zod';
import { getAllProducts as getAllProductsFromCache } from '../../stores/product-store';
import { getDashboardTags as getDashboardTagsFromCache } from '../../stores/product-tag-store';
import Fuse from 'fuse.js';

export const getNextDeliveryDate = async (productId: number): Promise<Date | null> => {
  const result = await db
    .select({ deliveryTime: deliverySlotInfo.deliveryTime })
    .from(productSlots)
    .innerJoin(deliverySlotInfo, eq(productSlots.slotId, deliverySlotInfo.id))
    .where(
      and(
        eq(productSlots.productId, productId),
        eq(deliverySlotInfo.isActive, true),
        gt(deliverySlotInfo.deliveryTime, sql`NOW()`)
      )
    )
    .orderBy(deliverySlotInfo.deliveryTime)
    .limit(1);


  return result[0]?.deliveryTime || null;
};





export const commonRouter = router({
  getDashboardTags: publicProcedure
    .query(async () => {
      // Get dashboard tags from cache
      const tags = await getDashboardTagsFromCache();

      return {
        tags: tags,
      };
    }),

  getAllProductsSummary: publicProcedure
    .input(z.object({
      searchQuery: z.string().optional(),
      tagId: z.number().optional()
    }))
    .query(async ({ input }) => {
      const { searchQuery, tagId } = input;

      // Get all products from cache
      let products = await getAllProductsFromCache();
      products = products.filter(item => Boolean(item.id))
      
      // Apply tag filtering if tagId is provided
      if (tagId) {
        // Get products that have this tag from the database
        const taggedProducts = await db
          .select({ productId: productTags.productId })
          .from(productTags)
          .where(eq(productTags.tagId, tagId));

        const taggedProductIds = new Set(taggedProducts.map(tp => tp.productId));

        // Filter products based on tag
        products = products.filter(product => taggedProductIds.has(product.id));
      }

      // Apply search filtering if searchQuery is provided using Fuse.js
      if (searchQuery) {
        const fuse = new Fuse(products, {
          keys: [
            'name',
            'shortDescription',
            'longDescription',
            'store.name', // Search in store name too
            'productTags', // Search in product tags too
          ],
          threshold: 0.3, // Adjust fuzziness (0.0 = exact match, 1.0 = match anything)
          includeScore: true,
          shouldSort: true,
        });

        const fuseResults = fuse.search(searchQuery);
        products = fuseResults.map(result => result.item);
      }

      // Get suspended product IDs to filter them out
      const suspendedProducts = await db
        .select({ id: productInfo.id })
        .from(productInfo)
        .where(eq(productInfo.isSuspended, true));

      const suspendedProductIds = new Set(suspendedProducts.map(sp => sp.id));

      // Filter out suspended products
      products = products.filter(product => !suspendedProductIds.has(product.id));

      // Format products to match the expected response structure
      const formattedProducts = await Promise.all(
        products.map(async (product) => {
          const nextDeliveryDate = await getNextDeliveryDate(product.id);
          return {
            id: product.id,
            name: product.name,
            shortDescription: product.shortDescription,
            price: parseFloat(product.price),
            marketPrice: product.marketPrice ? parseFloat(product.marketPrice) : null,
            unit: product.unitNotation,
            unitNotation: product.unitNotation,
            incrementStep: product.incrementStep,
            productQuantity: product.productQuantity,
            storeId: product.store?.id || null,
            isOutOfStock: product.isOutOfStock,
            nextDeliveryDate: nextDeliveryDate ? nextDeliveryDate.toISOString() : null,
            images: product.images, // Already signed URLs from cache
          };
        })
      );

      
      return {
        products: formattedProducts,
        count: formattedProducts.length,
      };
    }),

  getStoresSummary: publicProcedure
    .query(async () => {
      const stores = await db.query.storeInfo.findMany({
        columns: {
          id: true,
          name: true,
          description: true,
        },
      });

      return {
        stores,
      };
    }),

  healthCheck: publicProcedure
    .query(async () => {
      // Test DB connection by selecting product names
      await db.select({ name: productInfo.name }).from(productInfo).limit(1);

      return {
        status: "ok",
      };
    }),
});