# LittleShop Client SDK

A .NET client library for interacting with the LittleShop e-commerce API. This SDK provides a strongly-typed, easy-to-use interface for all LittleShop API endpoints with built-in authentication, retry policies, and error handling.

## Installation

Add the LittleShop.Client library to your project:

```bash
dotnet add reference ../LittleShop.Client/LittleShop.Client.csproj
```

Or via NuGet (when published):
```bash
dotnet add package LittleShop.Client
```

## Quick Start

### Basic Setup with Dependency Injection

```csharp
using LittleShop.Client.Extensions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((context, services) =>
    {
        // Add LittleShop client with configuration
        services.AddLittleShopClient(options =>
        {
            options.BaseUrl = "https://localhost:5001";
            options.TimeoutSeconds = 30;
            options.MaxRetryAttempts = 3;
            options.EnableLogging = true;
        });
    })
    .Build();

// Get the client from DI
var client = host.Services.GetRequiredService<ILittleShopClient>();
```

### Simple Console Application Example

```csharp
using LittleShop.Client;
using LittleShop.Client.Extensions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

// Setup DI container
var services = new ServiceCollection();
services.AddLogging(builder => builder.AddConsole());
services.AddLittleShopClient("https://localhost:5001");

var serviceProvider = services.BuildServiceProvider();
var client = serviceProvider.GetRequiredService<ILittleShopClient>();

// Authenticate
var loginResult = await client.Authentication.LoginAsync("admin", "admin");
if (loginResult.IsSuccess)
{
    Console.WriteLine($"Logged in as: {loginResult.Data.Username}");
    Console.WriteLine($"Token expires: {loginResult.Data.ExpiresAt}");
}

// Get categories
var categoriesResult = await client.Catalog.GetCategoriesAsync();
if (categoriesResult.IsSuccess)
{
    foreach (var category in categoriesResult.Data)
    {
        Console.WriteLine($"Category: {category.Name} - {category.Description}");
    }
}

// Get products with filtering
var productsResult = await client.Catalog.GetProductsAsync(
    pageNumber: 1,
    pageSize: 10,
    searchTerm: "wireless",
    minPrice: 10,
    maxPrice: 100
);

if (productsResult.IsSuccess)
{
    Console.WriteLine($"Found {productsResult.Data.TotalCount} products");
    foreach (var product in productsResult.Data.Items)
    {
        Console.WriteLine($"Product: {product.Name} - £{product.Price}");
    }
}
```

## Authentication

The SDK handles JWT authentication automatically. Once you log in, the token is stored and automatically included in subsequent requests.

```csharp
// Login
var loginResult = await client.Authentication.LoginAsync("username", "password");
if (!loginResult.IsSuccess)
{
    Console.WriteLine($"Login failed: {loginResult.ErrorMessage}");
    return;
}

// Check if authenticated
if (client.Authentication.IsAuthenticated())
{
    Console.WriteLine("User is authenticated");
}

// Get current token (if needed for external use)
var token = client.Authentication.GetToken();

// Logout
client.Authentication.Logout();
```

## Catalog Operations

### Get All Categories
```csharp
var result = await client.Catalog.GetCategoriesAsync();
if (result.IsSuccess)
{
    foreach (var category in result.Data)
    {
        Console.WriteLine($"{category.Name}: {category.Description}");
    }
}
```

### Get Products with Pagination and Filtering
```csharp
var result = await client.Catalog.GetProductsAsync(
    pageNumber: 1,
    pageSize: 20,
    categoryId: categoryGuid,     // Optional: Filter by category
    searchTerm: "headphones",      // Optional: Search term
    minPrice: 50,                  // Optional: Minimum price
    maxPrice: 200                  // Optional: Maximum price
);

if (result.IsSuccess)
{
    Console.WriteLine($"Page {result.Data.PageNumber} of {result.Data.TotalPages}");
    Console.WriteLine($"Total products: {result.Data.TotalCount}");
    
    foreach (var product in result.Data.Items)
    {
        Console.WriteLine($"{product.Name} - £{product.Price}");
        if (product.Photos.Any())
        {
            Console.WriteLine($"  Photo: {product.Photos.First().Url}");
        }
    }
}
```

### Get Single Product
```csharp
var result = await client.Catalog.GetProductByIdAsync(productId);
if (result.IsSuccess)
{
    var product = result.Data;
    Console.WriteLine($"Name: {product.Name}");
    Console.WriteLine($"Price: £{product.Price}");
    Console.WriteLine($"Weight: {product.Weight} {product.WeightUnit}");
}
```

## Order Operations

### Create Order
```csharp
var orderRequest = new CreateOrderRequest
{
    IdentityReference = "CUST123",
    ShippingName = "John Smith",
    ShippingAddress = "123 Main Street",
    ShippingCity = "London",
    ShippingPostCode = "SW1A 1AA",
    ShippingCountry = "United Kingdom",
    Notes = "Please deliver to reception",
    Items = new List<CreateOrderItem>
    {
        new CreateOrderItem 
        { 
            ProductId = productId1, 
            Quantity = 2 
        },
        new CreateOrderItem 
        { 
            ProductId = productId2, 
            Quantity = 1 
        }
    }
};

var result = await client.Orders.CreateOrderAsync(orderRequest);
if (result.IsSuccess)
{
    Console.WriteLine($"Order created: {result.Data.Id}");
    Console.WriteLine($"Total: £{result.Data.TotalAmount}");
}
```

### Get Orders by Customer Identity
```csharp
var result = await client.Orders.GetOrdersByIdentityAsync("CUST123");
if (result.IsSuccess)
{
    foreach (var order in result.Data)
    {
        Console.WriteLine($"Order {order.Id}: {order.Status} - £{order.TotalAmount}");
        Console.WriteLine($"  Created: {order.CreatedAt}");
        if (!string.IsNullOrEmpty(order.TrackingNumber))
        {
            Console.WriteLine($"  Tracking: {order.TrackingNumber}");
        }
    }
}
```

### Create Cryptocurrency Payment
```csharp
var result = await client.Orders.CreatePaymentAsync(orderId, "BTC");
if (result.IsSuccess)
{
    var payment = result.Data;
    Console.WriteLine($"Payment ID: {payment.Id}");
    Console.WriteLine($"Send {payment.RequiredAmount} {payment.Currency} to:");
    Console.WriteLine($"Address: {payment.WalletAddress}");
    Console.WriteLine($"Expires: {payment.ExpiresAt}");
    
    if (!string.IsNullOrEmpty(payment.BTCPayCheckoutUrl))
    {
        Console.WriteLine($"Or pay via: {payment.BTCPayCheckoutUrl}");
    }
}
```

## Error Handling

All API methods return an `ApiResponse<T>` wrapper that includes success status, data, and error information:

```csharp
var result = await client.Catalog.GetProductByIdAsync(productId);

if (result.IsSuccess)
{
    // Success - access data
    var product = result.Data;
    Console.WriteLine($"Product: {product.Name}");
}
else
{
    // Error - handle appropriately
    Console.WriteLine($"Error: {result.ErrorMessage}");
    Console.WriteLine($"Status Code: {result.StatusCode}");
    
    switch (result.StatusCode)
    {
        case HttpStatusCode.NotFound:
            Console.WriteLine("Product not found");
            break;
        case HttpStatusCode.Unauthorized:
            Console.WriteLine("Please login first");
            break;
        case HttpStatusCode.BadRequest:
            Console.WriteLine("Invalid request");
            break;
        default:
            Console.WriteLine("An error occurred");
            break;
    }
}
```

## Advanced Configuration

### Custom HTTP Client Configuration

The SDK uses Polly for retry policies and includes automatic retry for transient failures:

```csharp
services.AddLittleShopClient(options =>
{
    options.BaseUrl = "https://api.littleshop.com";
    options.TimeoutSeconds = 60;        // Request timeout
    options.MaxRetryAttempts = 5;       // Number of retries for transient failures
    options.EnableLogging = true;       // Enable detailed logging
});
```

### Using in ASP.NET Core Web Application

```csharp
// In Program.cs or Startup.cs
builder.Services.AddLittleShopClient(options =>
{
    options.BaseUrl = builder.Configuration["LittleShop:ApiUrl"];
    options.TimeoutSeconds = 30;
});

// In a controller or service
public class ProductController : Controller
{
    private readonly ILittleShopClient _client;
    
    public ProductController(ILittleShopClient client)
    {
        _client = client;
    }
    
    public async Task<IActionResult> Index()
    {
        var result = await _client.Catalog.GetProductsAsync();
        if (result.IsSuccess)
        {
            return View(result.Data.Items);
        }
        
        return View("Error", result.ErrorMessage);
    }
}
```

## Features

- ✅ **Strongly Typed Models** - All API responses are mapped to C# classes
- ✅ **Automatic Authentication** - JWT tokens are managed automatically
- ✅ **Retry Policies** - Automatic retry for transient failures
- ✅ **Error Handling** - Consistent error responses with detailed information
- ✅ **Logging Support** - Built-in logging for debugging
- ✅ **Dependency Injection** - Full DI support for ASP.NET Core applications
- ✅ **Async/Await** - All methods are async for better performance
- ✅ **Pagination Support** - Built-in pagination for product listings
- ✅ **Filtering & Search** - Advanced filtering options for products

## API Coverage

- **Authentication**
  - Login
  - Token refresh
  - Logout

- **Catalog**
  - Get all categories
  - Get category by ID
  - Get products (with pagination and filtering)
  - Get product by ID

- **Orders**
  - Create order
  - Get orders by customer identity
  - Get order by ID
  - Create cryptocurrency payment
  - Get order payments

## Requirements

- .NET 9.0 or later
- LittleShop API server running and accessible

## License

This SDK is part of the LittleShop e-commerce platform.