# Products API

The Products API provides methods for managing your product catalog, including CRUD operations, search, and pagination.

## Import

```typescript
import { Products } from 'lua-cli';
```

## Overview

The Products API allows you to:
- List all products with pagination
- Search products
- Get product by ID
- Create new products
- Update existing products
- Delete products

## Methods

### `Products.get(pageOrOptions?, limit?)`

Retrieves products with pagination and optional filtering. Supports both legacy (page, limit) and new (options object) signatures.

**Signatures:**
```typescript
// Legacy signature
Products.get(page?: number, limit?: number): Promise<ProductPaginationInstance>

// New signature (v3.2.0+)
Products.get(options?: ProductFilterOptions): Promise<ProductPaginationInstance>
```

**Parameters (Legacy):**
- `page` (number, optional) - Page number (default: 1)
- `limit` (number, optional) - Items per page (default: 10)

**Parameters (Options Object):**
- `options.page` (number, optional) - Page number
- `options.limit` (number, optional) - Items per page
- `options.filter` (object, optional) - MongoDB-style filter criteria

**Returns:** `Promise<ProductPaginationInstance>`

**Example:**
```typescript
// Get first page (10 items)
const products = await Products.get();

// Legacy: Get page 2 with 20 items
const page2 = await Products.get(2, 20);

// New: Get products with options object
const page3 = await Products.get({ page: 3, limit: 20 });

// Filter products by category
const electronics = await Products.get({ filter: { category: "Electronics" } });

// Filter with MongoDB operators
const affordable = await Products.get({ 
  filter: { price: { $lte: 100 }, inStock: true } 
});

// Combine pagination and filter
const filtered = await Products.get({
  page: 1,
  limit: 10,
  filter: { category: "Clothing", price: { $gte: 20, $lte: 50 } }
});

// Access products
for (const product of products) {
  console.log(product.name, product.price);
}

// Pagination info
console.log(products.pagination.totalPages);
console.log(products.pagination.hasNextPage);

// Navigate pages
if (products.pagination.hasNextPage) {
  const nextPage = await products.nextPage();
}
```

**Supported Filter Operators:**
- `$eq` - Equal to
- `$ne` - Not equal to
- `$gt` - Greater than
- `$gte` - Greater than or equal
- `$lt` - Less than
- `$lte` - Less than or equal
- `$in` - In array
- `$nin` - Not in array

### `Products.search(query, limit?)`

Searches products by name or description.

**Parameters:**
- `query` (string) - Search term
- `limit` (number, optional) - Max results (default: 10)

**Returns:** `Promise<ProductSearchInstance>`

**Example:**
```typescript
const results = await Products.search('laptop');

// Access results
for (const product of results) {
  console.log(product.name, product.price);
}

// Results length
console.log(`Found ${results.length} products`);
```

### `Products.getById(productId)`

Retrieves a single product by ID.

**Parameters:**
- `productId` (string) - Product ID

**Returns:** `Promise<ProductInstance | null>`

**Example:**
```typescript
const product = await Products.getById('prod_123');

if (product) {
  console.log(product.name);
  console.log(product.price);
  console.log(product.stock);
} else {
  console.log('Product not found');
}
```

### `Products.create(productData)`

Creates a new product.

**Parameters:**
- `productData` (object) - Product information

**Returns:** `Promise<ProductInstance>`

**Example:**
```typescript
const product = await Products.create({
  name: 'Wireless Mouse',
  description: 'Ergonomic wireless mouse with USB receiver',
  price: 29.99,
  stock: 100,
  category: 'Electronics',
  sku: 'WM-001',
  metadata: {
    brand: 'TechCorp',
    warranty: '1 year'
  }
});

console.log('Created product:', product.id);
```

### `Products.update(productData, productId)`

Updates an existing product.

**Parameters:**
- `productData` (object) - Updated product data
- `productId` (string) - Product ID to update

**Returns:** `Promise<{ updated: boolean; product: Product }>`

**Example:**
```typescript
const result = await Products.update({
  price: 24.99,
  stock: 150
}, 'prod_123');

if (result.updated) {
  console.log('Product updated');
}
```

### `Products.delete(productId)`

Deletes a product.

**Parameters:**
- `productId` (string) - Product ID to delete

**Returns:** `Promise<DeleteProductResponse>`

**Example:**
```typescript
const result = await Products.delete('prod_123');

if (result.deleted) {
  console.log('Product deleted');
}
```

## ProductInstance

Product objects have convenient methods:

### `product.update(data)`

Updates this product.

**Example:**
```typescript
const product = await Products.getById('prod_123');

await product.update({
  price: 19.99,
  stock: 200
});
```

### `product.delete()`

Deletes this product.

**Example:**
```typescript
const product = await Products.getById('prod_123');
await product.delete();
```

### `product.save()`

Saves modifications to the product.

**Example:**
```typescript
const product = await Products.getById('prod_123');

// Modify properties
product.price = 24.99;
product.stock = 75;

// Save changes
await product.save();
```

### Property Access

```typescript
const product = await Products.getById('prod_123');

// Direct access (via Proxy)
console.log(product.name);
console.log(product.price);
console.log(product.stock);

// Or via .data
console.log(product.data.name);
console.log(product.data.price);
```

## Complete Examples

### Product Search Tool

```typescript
import { LuaTool, Products } from 'lua-cli/skill';
import { z } from 'zod';

export default class SearchProductsTool implements LuaTool {
  name = 'search_products';
  description = 'Search for products by name or description';
  
  inputSchema = z.object({
    query: z.string().describe('Search term'),
    maxResults: z.number().min(1).max(50).optional()
  });
  
  async execute(input: z.infer<typeof this.inputSchema>) {
    const results = await Products.search(
      input.query,
      input.maxResults || 10
    );
    
    return {
      success: true,
      count: results.length,
      products: results.map(p => ({
        id: p.id,
        name: p.name,
        price: p.price,
        inStock: (p.stock || 0) > 0
      }))
    };
  }
}
```

### Product Management Tool

```typescript
import { LuaTool, Products } from 'lua-cli/skill';
import { z } from 'zod';

export default class ManageProductTool implements LuaTool {
  name = 'manage_product';
  description = 'Create, update, or delete products';
  
  inputSchema = z.object({
    action: z.enum(['create', 'update', 'delete']),
    productId: z.string().optional(),
    name: z.string().optional(),
    price: z.number().optional(),
    stock: z.number().optional()
  });
  
  async execute(input: z.infer<typeof this.inputSchema>) {
    switch (input.action) {
      case 'create':
        if (!input.name || !input.price) {
          return { success: false, error: 'Name and price required' };
        }
        
        const product = await Products.create({
          name: input.name,
          price: input.price,
          stock: input.stock || 0
        });
        
        return {
          success: true,
          action: 'created',
          productId: product.id
        };
        
      case 'update':
        if (!input.productId) {
          return { success: false, error: 'Product ID required' };
        }
        
        const updates: any = {};
        if (input.name) updates.name = input.name;
        if (input.price) updates.price = input.price;
        if (input.stock !== undefined) updates.stock = input.stock;
        
        const result = await Products.update(updates, input.productId);
        
        return {
          success: result.updated,
          action: 'updated',
          productId: input.productId
        };
        
      case 'delete':
        if (!input.productId) {
          return { success: false, error: 'Product ID required' };
        }
        
        const deleteResult = await Products.delete(input.productId);
        
        return {
          success: deleteResult.deleted,
          action: 'deleted',
          productId: input.productId
        };
    }
  }
}
```

### Low Stock Alert

```typescript
import { LuaTool, Products, User } from 'lua-cli/skill';
import { z } from 'zod';

export default class CheckLowStockTool implements LuaTool {
  name = 'check_low_stock';
  description = 'Check for products with low stock and alert user';
  
  inputSchema = z.object({
    threshold: z.number().min(0).default(10)
  });
  
  async execute(input: z.infer<typeof this.inputSchema>) {
    // Get all products
    const allProducts = await Products.get(1, 100);
    
    // Filter low stock items
    const lowStock = allProducts.filter(p => 
      (p.stock || 0) < input.threshold && (p.stock || 0) > 0
    );
    
    if (lowStock.length > 0) {
      // Alert user
      const user = await User.get();
      const message = `⚠️ Low Stock Alert:\n\n` +
        lowStock.map(p => 
          `- ${p.name}: ${p.stock} remaining`
        ).join('\n');
      
      await user.send([{ type: 'text', text: message }]);
    }
    
    return {
      success: true,
      lowStockCount: lowStock.length,
      products: lowStock.map(p => ({
        id: p.id,
        name: p.name,
        stock: p.stock
      }))
    };
  }
}
```

## Product Data Structure

```typescript
interface Product {
  id: string;
  name: string;
  description?: string;
  price: number;
  stock?: number;
  category?: string;
  sku?: string;
  images?: string[];
  metadata?: Record<string, any>;
  createdAt?: string;
  updatedAt?: string;
}
```

## Pagination

The `ProductPaginationInstance` provides:

```typescript
interface ProductPaginationInstance {
  products: ProductInstance[];
  pagination: {
    currentPage: number;
    totalPages: number;
    totalCount: number;
    limit: number;
    hasNextPage: boolean;
    hasPrevPage: boolean;
    nextPage: number | null;
    prevPage: number | null;
  };
  
  // Methods
  nextPage(): Promise<ProductPaginationInstance>;
  prevPage(): Promise<ProductPaginationInstance>;
  
  // Array-like methods
  map<T>(callback: (product: ProductInstance) => T): T[];
  filter(callback: (product: ProductInstance) => boolean): ProductInstance[];
  forEach(callback: (product: ProductInstance) => void): void;
  find(callback: (product: ProductInstance) => boolean): ProductInstance | undefined;
}
```

## Error Handling

```typescript
try {
  const product = await Products.getById(productId);
  
  if (!product) {
    return {
      success: false,
      error: 'Product not found',
      productId
    };
  }
  
  // Process product...
} catch (error) {
  return {
    success: false,
    error: error instanceof Error ? error.message : 'Unknown error'
  };
}
```

## Related APIs

- [Baskets API](./Baskets.md) - Add products to cart
- [Orders API](./Orders.md) - Process product orders
- [Data API](./Data.md) - Store product metadata

## See Also

- [ProductInstance Documentation](./instances/ProductInstance.md)
- [Product Tools Example](../../template/src/skills/tools/ProductsTool.ts)
- [E-commerce Patterns](../guides/EcommercePatterns.md)

