import type { H3Event } from 'h3'
import { and, eq, inArray, asc } from 'drizzle-orm'
import { carts, cartItems, products } from '../database/schema'

// Re-export shared types
export type { CartItemWithProduct, CartSummary } from '~/types/cart'
import type { CartItemWithProduct, CartSummary } from '~/types/cart'

/**
 * Get or create a cart for the current user/session
 *
 * @param event - H3 event object
 * @returns Cart record
 */
export async function getOrCreateCart(event: H3Event) {
  const db = useDatabase()
  const { user } = await getUserSession(event)

  if (user) {
    // Authenticated user - find or create cart by userId
    let cart = await db.query.carts.findFirst({
      where: eq(carts.userId, user.id),
    })

    if (!cart) {
      // Create new cart for user
      const [newCart] = await db
        .insert(carts)
        .values({
          userId: user.id,
          sessionId: '', // Empty for user carts (not used)
        })
        .returning()
      cart = newCart
    }

    return cart
  } else {
    // Guest user - find or create cart by sessionId
    const sessionId = getOrCreateSessionId(event)

    let cart = await db.query.carts.findFirst({
      where: and(eq(carts.sessionId, sessionId), eq(carts.userId, null)),
    })

    if (!cart) {
      // Create new cart for guest
      const [newCart] = await db
        .insert(carts)
        .values({
          userId: null,
          sessionId,
        })
        .returning()
      cart = newCart
    }

    return cart
  }
}

/**
 * Get cart with all items and product details
 *
 * Automatically filters out unavailable products (inactive or out of stock)
 * and removes them from the cart.
 *
 * @param cartId - Cart UUID
 * @returns Cart summary with items, totals, and removed items
 */
export async function getCartWithItems(cartId: string): Promise<CartSummary> {
  const db = useDatabase()

  // Fetch cart
  const cart = await db.query.carts.findFirst({
    where: eq(carts.id, cartId),
  })

  if (!cart) {
    throw createError({
      statusCode: 404,
      statusMessage: 'Cart not found',
    })
  }

  // Fetch cart items with product details
  const items = await db.query.cartItems.findMany({
    where: eq(cartItems.cartId, cartId),
    with: {
      product: true,
    },
    orderBy: asc(cartItems.addedAt), // Sort by addedAt to maintain stable order
  })

  // Separate available and unavailable items
  const availableItems: CartItemWithProduct[] = []
  const unavailableItemIds: string[] = []
  const removedProductNames: string[] = []

  for (const item of items) {
    // Check if product is available
    const isAvailable = item.product.active && item.product.stockQuantity >= item.quantity

    if (isAvailable) {
      // Add to available items with subtotal calculation
      availableItems.push({
        id: item.id,
        cartId: item.cartId,
        productId: item.productId,
        quantity: item.quantity,
        addedAt: item.addedAt,
        product: {
          id: item.product.id,
          name: item.product.name,
          description: item.product.description,
          price: item.product.price,
          stockQuantity: item.product.stockQuantity,
          active: item.product.active,
          category: item.product.category,
          imageUrl: item.product.imageUrl,
          navProductId: item.product.navProductId,
        },
        subtotal: Number.parseFloat(item.product.price) * item.quantity,
      })
    } else {
      // Mark for removal
      unavailableItemIds.push(item.id)
      removedProductNames.push(item.product.name)
    }
  }

  // Remove unavailable items from cart
  if (unavailableItemIds.length > 0) {
    await db.delete(cartItems).where(inArray(cartItems.id, unavailableItemIds))

    // Update cart's updatedAt timestamp
    await db
      .update(carts)
      .set({ updatedAt: new Date() })
      .where(eq(carts.id, cartId))
  }

  // Calculate total
  const total = availableItems.reduce((sum, item) => sum + item.subtotal, 0)
  const itemCount = availableItems.reduce((sum, item) => sum + item.quantity, 0)

  return {
    cart,
    items: availableItems,
    total,
    itemCount,
    ...(removedProductNames.length > 0 && { removedItems: removedProductNames }),
  }
}

/**
 * Update cart's updated_at timestamp
 *
 * @param cartId - Cart UUID
 */
export async function touchCart(cartId: string): Promise<void> {
  const db = useDatabase()
  await db
    .update(carts)
    .set({ updatedAt: new Date() })
    .where(eq(carts.id, cartId))
}

/**
 * Check if a cart item belongs to the current user/session
 *
 * @param event - H3 event object
 * @param cartItemId - Cart item UUID
 * @returns true if item belongs to current user/session, false otherwise
 */
export async function verifyCartItemOwnership(
  event: H3Event,
  cartItemId: string
): Promise<boolean> {
  const db = useDatabase()
  const { user } = await getUserSession(event)

  // Fetch cart item with cart details
  const item = await db.query.cartItems.findFirst({
    where: eq(cartItems.id, cartItemId),
    with: {
      cart: true,
    },
  })

  if (!item) {
    return false
  }

  // Check ownership
  if (user) {
    // Authenticated user - check userId match
    return item.cart.userId === user.id
  } else {
    // Guest user - check sessionId match
    const sessionId = getSessionId(event)
    return sessionId !== null && item.cart.sessionId === sessionId && item.cart.userId === null
  }
}
