import { router, protectedProcedure, publicProcedure } from '@/src/trpc/trpc-index';
import { z } from 'zod';
import { db } from '@/src/db/db_index';
import { cartItems, productInfo, units, productSlots, deliverySlotInfo } from '@/src/db/schema';
import { eq, and, sql, inArray, gt } from 'drizzle-orm';
import { ApiError } from '@/src/lib/api-error';
import { generateSignedUrlsFromS3Urls, scaffoldAssetUrl } from '@/src/lib/s3-client';
import { getProductSlots, getMultipleProductsSlots } from '@/src/stores/slot-store';

interface CartResponse {
  items: any[];
  totalItems: number;
  totalAmount: number;
}

const getCartData = async (userId: number): Promise<CartResponse> => {
  const cartItemsWithProducts = await db
    .select({
      cartId: cartItems.id,
      productId: productInfo.id,
      productName: productInfo.name,
      productPrice: productInfo.price,
      productImages: productInfo.images,
      productQuantity: productInfo.productQuantity,
      isOutOfStock: productInfo.isOutOfStock,
      unitShortNotation: units.shortNotation,
      quantity: cartItems.quantity,
      addedAt: cartItems.addedAt,
    })
    .from(cartItems)
    .innerJoin(productInfo, eq(cartItems.productId, productInfo.id))
    .innerJoin(units, eq(productInfo.unitId, units.id))
    .where(eq(cartItems.userId, userId));

  // Generate signed URLs for images
      const cartWithSignedUrls = await Promise.all(
      cartItemsWithProducts.map(async (item) => ({
        id: item.cartId,
        productId: item.productId,
        quantity: parseFloat(item.quantity),
        addedAt: item.addedAt,
        product: {
          id: item.productId,
          name: item.productName,
          price: item.productPrice,
          productQuantity: item.productQuantity,
          unit: item.unitShortNotation,
          isOutOfStock: item.isOutOfStock,
          images: scaffoldAssetUrl((item.productImages as string[]) || []),
        },
        subtotal: parseFloat(item.productPrice.toString()) * parseFloat(item.quantity),
      }))
    );

  const totalAmount = cartWithSignedUrls.reduce((sum, item) => sum + item.subtotal, 0);

  return {
    items: cartWithSignedUrls,
    totalItems: cartWithSignedUrls.length,
    totalAmount,
  };
};

export const cartRouter = router({
  getCart: protectedProcedure
    .query(async ({ ctx }): Promise<CartResponse> => {
      const userId = ctx.user.userId;
      return await getCartData(userId);
    }),

  addToCart: protectedProcedure
    .input(z.object({
      productId: z.number().int().positive(),
      quantity: z.number().int().positive(),
    }))
    .mutation(async ({ input, ctx }): Promise<CartResponse> => {
      const userId = ctx.user.userId;
      const { productId, quantity } = input;

      // Validate input
      if (!productId || !quantity || quantity <= 0) {
        throw new ApiError("Product ID and positive quantity required", 400);
      }

      // Check if product exists
      const product = await db.query.productInfo.findFirst({
        where: eq(productInfo.id, productId),
      });

      if (!product) {
        throw new ApiError("Product not found", 404);
      }

      // Check if item already exists in cart
      const existingItem = await db.query.cartItems.findFirst({
        where: and(eq(cartItems.userId, userId), eq(cartItems.productId, productId)),
      });

      if (existingItem) {
        // Update quantity
        await db.update(cartItems)
          .set({
            quantity: sql`${cartItems.quantity} + ${quantity}`,
          })
          .where(eq(cartItems.id, existingItem.id));
      } else {
        // Insert new item
        await db.insert(cartItems).values({
          userId,
          productId,
          quantity: quantity.toString(),
        });
      }

      // Return updated cart
      return await getCartData(userId);
    }),

  updateCartItem: protectedProcedure
    .input(z.object({
      itemId: z.number().int().positive(),
      quantity: z.number().int().min(0),
    }))
    .mutation(async ({ input, ctx }): Promise<CartResponse> => {
      const userId = ctx.user.userId;
      const { itemId, quantity } = input;

      if (!quantity || quantity <= 0) {
        throw new ApiError("Positive quantity required", 400);
      }

      const [updatedItem] = await db.update(cartItems)
        .set({ quantity: quantity.toString() })
        .where(and(
          eq(cartItems.id, itemId),
          eq(cartItems.userId, userId)
        ))
        .returning();

      if (!updatedItem) {
        throw new ApiError("Cart item not found", 404);
      }

      // Return updated cart
      return await getCartData(userId);
    }),

  removeFromCart: protectedProcedure
    .input(z.object({
      itemId: z.number().int().positive(),
    }))
    .mutation(async ({ input, ctx }): Promise<CartResponse> => {
      const userId = ctx.user.userId;
      const { itemId } = input;

      const [deletedItem] = await db.delete(cartItems)
        .where(and(
          eq(cartItems.id, itemId),
          eq(cartItems.userId, userId)
        ))
        .returning();

      if (!deletedItem) {
        throw new ApiError("Cart item not found", 404);
      }

      // Return updated cart
      return await getCartData(userId);
    }),

  clearCart: protectedProcedure
    .mutation(async ({ ctx }) => {
      const userId = ctx.user.userId;

      await db.delete(cartItems).where(eq(cartItems.userId, userId));

      return {
        items: [],
        totalItems: 0,
        totalAmount: 0,
        message: "Cart cleared successfully",
      };
    }),

  // Original DB-based getCartSlots (commented out)
  // getCartSlots: publicProcedure
  //   .input(z.object({
  //     productIds: z.array(z.number().int().positive())
  //   }))
  //   .query(async ({ input }) => {
  //     const { productIds } = input;
  //
  //     if (productIds.length === 0) {
  //       return {};
  //     }
  //
  //     // Get slots for these products where freeze time is after current time
  //     const slotsData = await db
  //       .select({
  //         productId: productSlots.productId,
  //         slotId: deliverySlotInfo.id,
  //         deliveryTime: deliverySlotInfo.deliveryTime,
  //         freezeTime: deliverySlotInfo.freezeTime,
  //         isActive: deliverySlotInfo.isActive,
  //       })
  //       .from(productSlots)
  //       .innerJoin(deliverySlotInfo, eq(productSlots.slotId, deliverySlotInfo.id))
  //       .where(and(
  //         inArray(productSlots.productId, productIds),
  //         gt(deliverySlotInfo.freezeTime, sql`NOW()`),
  //         eq(deliverySlotInfo.isActive, true)
  //       ));
  //
  //     // Group by productId
  //     const result: Record<number, any[]> = {};
  //     slotsData.forEach(slot => {
  //       if (!result[slot.productId]) {
  //         result[slot.productId] = [];
  //       }
  //       result[slot.productId].push({
  //         id: slot.slotId,
  //         deliveryTime: slot.deliveryTime,
  //         freezeTime: slot.freezeTime,
  //       });
  //     });
  //
  //     return result;
  //   }),

  // Cache-based getCartSlots
  getCartSlots: publicProcedure
    .input(z.object({
      productIds: z.array(z.number().int().positive())
    }))
    .query(async ({ input }) => {
      const { productIds } = input;

      if (productIds.length === 0) {
        return {};
      }

      return await getMultipleProductsSlots(productIds);
    }),
});
